From 8976f7a9e185b7ae7a447fc0e87340ad4a999119 Mon Sep 17 00:00:00 2001 From: Yongrui Lin Date: Tue, 9 Jun 2026 20:49:10 +0000 Subject: [PATCH 01/10] Declaratively validate Toleration.Key as k8s-label-key Tag corev1.Toleration.Key (alpha) and mark the shared handwritten error covered via an opt-in KeyFormatCovered option, so the annotation-encoded path stays authoritative. Add a RuntimeClass spec.scheduling normalization rule for the v1alpha1 cross-version path. --- pkg/apis/core/validation/validation.go | 28 ++++++++++++++++--- pkg/apis/node/validation/validation.go | 12 ++++++-- staging/src/k8s.io/api/core/v1/types.go | 4 +++ staging/src/k8s.io/api/node/v1/types.go | 2 ++ staging/src/k8s.io/api/node/v1alpha1/types.go | 2 ++ staging/src/k8s.io/api/node/v1beta1/types.go | 2 ++ 6 files changed, 43 insertions(+), 7 deletions(-) diff --git a/pkg/apis/core/validation/validation.go b/pkg/apis/core/validation/validation.go index 4ce2f2b2b42..780505dec75 100644 --- a/pkg/apis/core/validation/validation.go +++ b/pkg/apis/core/validation/validation.go @@ -4315,7 +4315,7 @@ func validateOnlyAddedTolerations(newTolerations []core.Toleration, oldToleratio } } - allErrs = append(allErrs, ValidateTolerations(newTolerations, fldPath, opts)...) + allErrs = append(allErrs, ValidateTolerations(newTolerations, fldPath, opts, KeyFormatCovered)...) return allErrs } @@ -4352,14 +4352,34 @@ func ValidateHostAliases(hostAliases []core.HostAlias, fldPath *field.Path) fiel return allErrs } +// ValidateTolerationsOption is an option for ValidateTolerations that marks +// which handwritten validation error messages are covered by declarative +// validation. +type ValidateTolerationsOption int + +const ( + // KeyFormatCovered indicates the toleration key format check is + // covered by declarative validation. It must only be passed by callers whose + // tolerations are validated declaratively (the structured PodSpec.tolerations + // and RuntimeClass.scheduling.tolerations fields). It must NOT be passed by + // ValidateTolerationsInPodAnnotations, whose tolerations are parsed from an + // annotation string and have no declarative counterpart. + KeyFormatCovered ValidateTolerationsOption = iota +) + // ValidateTolerations tests if given tolerations have valid data. -func ValidateTolerations(tolerations []core.Toleration, fldPath *field.Path, opts PodValidationOptions) field.ErrorList { +func ValidateTolerations(tolerations []core.Toleration, fldPath *field.Path, opts PodValidationOptions, validationOpts ...ValidateTolerationsOption) field.ErrorList { allErrors := field.ErrorList{} + keyFormatCovered := slices.Contains(validationOpts, KeyFormatCovered) for i, toleration := range tolerations { idxPath := fldPath.Index(i) // validate the toleration key if len(toleration.Key) > 0 { - allErrors = append(allErrors, unversionedvalidation.ValidateLabelName(toleration.Key, idxPath.Child("key"))...) + keyErrs := unversionedvalidation.ValidateLabelName(toleration.Key, idxPath.Child("key")) + if keyFormatCovered { + keyErrs = keyErrs.MarkCoveredByDeclarative() + } + allErrors = append(allErrors, keyErrs...) } // empty toleration key with Exists operator and empty value means match all taints @@ -4688,7 +4708,7 @@ func ValidatePodSpec(spec *core.PodSpec, podMeta *metav1.ObjectMeta, fldPath *fi } if len(spec.Tolerations) > 0 { - allErrs = append(allErrs, ValidateTolerations(spec.Tolerations, fldPath.Child("tolerations"), opts)...) + allErrs = append(allErrs, ValidateTolerations(spec.Tolerations, fldPath.Child("tolerations"), opts, KeyFormatCovered)...) } if len(spec.HostAliases) > 0 { diff --git a/pkg/apis/node/validation/validation.go b/pkg/apis/node/validation/validation.go index b2b682d16d6..731d86afeda 100644 --- a/pkg/apis/node/validation/validation.go +++ b/pkg/apis/node/validation/validation.go @@ -26,13 +26,19 @@ import ( "regexp" ) -// Define normalization rules to handle field name differences across API versions -// v1alpha1 uses "spec.runtimeHandler" while v1/v1beta1 use "handler" +// Define normalization rules to handle field name differences across API versions. +// v1alpha1 nests fields under "spec" (e.g. "spec.runtimeHandler", "spec.scheduling") +// while v1/v1beta1 expose them at the top level ("handler", "scheduling"), matching +// the internal type used by handwritten validation. var NodeNormalizationRules = []field.NormalizationRule{ { Regexp: regexp.MustCompile(`^spec\.runtimeHandler(.*)$`), Replacement: "handler$1", }, + { + Regexp: regexp.MustCompile(`^spec\.scheduling(.*)$`), + Replacement: "scheduling$1", + }, } // ValidateRuntimeClass validates the RuntimeClass @@ -81,7 +87,7 @@ func validateScheduling(s *node.Scheduling, fldPath *field.Path) field.ErrorList } func validateTolerations(tolerations []core.Toleration, fldPath *field.Path) field.ErrorList { - allErrs := corevalidation.ValidateTolerations(tolerations, fldPath, corevalidation.PodValidationOptions{}) + allErrs := corevalidation.ValidateTolerations(tolerations, fldPath, corevalidation.PodValidationOptions{}, corevalidation.KeyFormatCovered) // Ensure uniquenes of tolerations. tolerationSet := map[core.Toleration]bool{} for i, t := range tolerations { diff --git a/staging/src/k8s.io/api/core/v1/types.go b/staging/src/k8s.io/api/core/v1/types.go index b49783370c1..dc3ef561aa4 100644 --- a/staging/src/k8s.io/api/core/v1/types.go +++ b/staging/src/k8s.io/api/core/v1/types.go @@ -4094,6 +4094,8 @@ type Toleration struct { // Key is the taint key that the toleration applies to. Empty means match all taint keys. // If the key is empty, operator must be Exists; this combination means to match all values and all keys. // +optional + // +k8s:alpha(since: "1.37")=+k8s:optional + // +k8s:alpha(since: "1.37")=+k8s:format=k8s-label-key Key string `json:"key,omitempty" protobuf:"bytes,1,opt,name=key"` // Operator represents a key's relationship to the value. // Valid operators are Exists, Equal, Lt, and Gt. Defaults to Equal. @@ -4295,6 +4297,7 @@ type PodSpec struct { // If specified, the pod's tolerations. // +optional // +listType=atomic + // +k8s:alpha(since: "1.37")=+k8s:optional Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"` // HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts // file if specified. @@ -5616,6 +5619,7 @@ type ReplicationControllerSpec struct { // The only allowed template.spec.restartPolicy value is "Always". // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template // +optional + // +k8s:alpha(since: "1.37")=+k8s:optional Template *PodTemplateSpec `json:"template,omitempty" protobuf:"bytes,3,opt,name=template"` } diff --git a/staging/src/k8s.io/api/node/v1/types.go b/staging/src/k8s.io/api/node/v1/types.go index aa41e561baa..51105d49248 100644 --- a/staging/src/k8s.io/api/node/v1/types.go +++ b/staging/src/k8s.io/api/node/v1/types.go @@ -67,6 +67,7 @@ type RuntimeClass struct { // If scheduling is nil, this RuntimeClass is assumed to be supported by all // nodes. // +optional + // +k8s:alpha(since: "1.37")=+k8s:optional Scheduling *Scheduling `json:"scheduling,omitempty" protobuf:"bytes,4,opt,name=scheduling"` } @@ -94,6 +95,7 @@ type Scheduling struct { // tolerated by the pod and the RuntimeClass. // +optional // +listType=atomic + // +k8s:alpha(since: "1.37")=+k8s:optional Tolerations []corev1.Toleration `json:"tolerations,omitempty" protobuf:"bytes,2,rep,name=tolerations"` } diff --git a/staging/src/k8s.io/api/node/v1alpha1/types.go b/staging/src/k8s.io/api/node/v1alpha1/types.go index 0ce65ecdb53..ac3f7475133 100644 --- a/staging/src/k8s.io/api/node/v1alpha1/types.go +++ b/staging/src/k8s.io/api/node/v1alpha1/types.go @@ -77,6 +77,7 @@ type RuntimeClassSpec struct { // If scheduling is nil, this RuntimeClass is assumed to be supported by all // nodes. // +optional + // +k8s:alpha(since: "1.37")=+k8s:optional Scheduling *Scheduling `json:"scheduling,omitempty" protobuf:"bytes,3,opt,name=scheduling"` } @@ -104,6 +105,7 @@ type Scheduling struct { // tolerated by the pod and the RuntimeClass. // +optional // +listType=atomic + // +k8s:alpha(since: "1.37")=+k8s:optional Tolerations []corev1.Toleration `json:"tolerations,omitempty" protobuf:"bytes,2,rep,name=tolerations"` } diff --git a/staging/src/k8s.io/api/node/v1beta1/types.go b/staging/src/k8s.io/api/node/v1beta1/types.go index 04b9733e22f..bde9f97ed7f 100644 --- a/staging/src/k8s.io/api/node/v1beta1/types.go +++ b/staging/src/k8s.io/api/node/v1beta1/types.go @@ -68,6 +68,7 @@ type RuntimeClass struct { // If scheduling is nil, this RuntimeClass is assumed to be supported by all // nodes. // +optional + // +k8s:alpha(since: "1.37")=+k8s:optional Scheduling *Scheduling `json:"scheduling,omitempty" protobuf:"bytes,4,opt,name=scheduling"` } @@ -95,6 +96,7 @@ type Scheduling struct { // tolerated by the pod and the RuntimeClass. // +optional // +listType=atomic + // +k8s:alpha(since: "1.37")=+k8s:optional Tolerations []corev1.Toleration `json:"tolerations,omitempty" protobuf:"bytes,2,rep,name=tolerations"` } From eb5a4ca1927ab550021aaa94eea7041e53dd68a9 Mon Sep 17 00:00:00 2001 From: Yongrui Lin Date: Tue, 9 Jun 2026 20:49:10 +0000 Subject: [PATCH 02/10] apps: declare /scale subresource for declarative validation The toleration rule makes the workload types DV roots; scale updates validate the parent under /scale, so the dispatch must handle it (as ReplicationController already does). --- staging/src/k8s.io/api/apps/v1/types.go | 3 +++ staging/src/k8s.io/api/apps/v1beta1/types.go | 2 ++ staging/src/k8s.io/api/apps/v1beta2/types.go | 3 +++ 3 files changed, 8 insertions(+) diff --git a/staging/src/k8s.io/api/apps/v1/types.go b/staging/src/k8s.io/api/apps/v1/types.go index 7a7ef684687..1c868a0dcfa 100644 --- a/staging/src/k8s.io/api/apps/v1/types.go +++ b/staging/src/k8s.io/api/apps/v1/types.go @@ -46,6 +46,7 @@ const ( // // The StatefulSet guarantees that a given network identity will always // map to the same storage identity. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" type StatefulSet struct { metav1.TypeMeta `json:""` @@ -369,6 +370,7 @@ type StatefulSetList struct { // +k8s:prerelease-lifecycle-gen:introduced=1.9 // Deployment enables declarative updates for Pods and ReplicaSets. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" type Deployment struct { metav1.TypeMeta `json:""` @@ -838,6 +840,7 @@ type DaemonSetList struct { // +k8s:prerelease-lifecycle-gen:introduced=1.9 // ReplicaSet ensures that a specified number of pod replicas are running at any given time. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" type ReplicaSet struct { metav1.TypeMeta `json:""` diff --git a/staging/src/k8s.io/api/apps/v1beta1/types.go b/staging/src/k8s.io/api/apps/v1beta1/types.go index 5e2d86df3be..2e7a0d505a3 100644 --- a/staging/src/k8s.io/api/apps/v1beta1/types.go +++ b/staging/src/k8s.io/api/apps/v1beta1/types.go @@ -98,6 +98,7 @@ type Scale struct { // // The StatefulSet guarantees that a given network identity will always // map to the same storage identity. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" type StatefulSet struct { metav1.TypeMeta `json:""` @@ -416,6 +417,7 @@ type StatefulSetList struct { // DEPRECATED - This group version of Deployment is deprecated by apps/v1beta2/Deployment. See the release notes for // more information. // Deployment enables declarative updates for Pods and ReplicaSets. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" type Deployment struct { metav1.TypeMeta `json:""` diff --git a/staging/src/k8s.io/api/apps/v1beta2/types.go b/staging/src/k8s.io/api/apps/v1beta2/types.go index 62c8117483c..192e6150c85 100644 --- a/staging/src/k8s.io/api/apps/v1beta2/types.go +++ b/staging/src/k8s.io/api/apps/v1beta2/types.go @@ -104,6 +104,7 @@ type Scale struct { // // The StatefulSet guarantees that a given network identity will always // map to the same storage identity. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" type StatefulSet struct { metav1.TypeMeta `json:""` @@ -424,6 +425,7 @@ type StatefulSetList struct { // DEPRECATED - This group version of Deployment is deprecated by apps/v1/Deployment. See the release notes for // more information. // Deployment enables declarative updates for Pods and ReplicaSets. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" type Deployment struct { metav1.TypeMeta `json:""` @@ -903,6 +905,7 @@ type DaemonSetList struct { // DEPRECATED - This group version of ReplicaSet is deprecated by apps/v1/ReplicaSet. See the release notes for // more information. // ReplicaSet ensures that a specified number of pod replicas are running at any given time. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" type ReplicaSet struct { metav1.TypeMeta `json:""` From ac386895dd6c5e2a9d65a454630b259e53b8fd5c Mon Sep 17 00:00:00 2001 From: Yongrui Lin Date: Tue, 9 Jun 2026 20:50:15 +0000 Subject: [PATCH 03/10] core: declare pod /eviction and /resize subresources for declarative validation Pod is now a DV root, and eviction and resize each do a pod store.Update under their subresource, so the dispatch must handle them or fail with "no validation found" (this broke kubectl drain). binding is unaffected (GuaranteedUpdate). --- staging/src/k8s.io/api/core/v1/types.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/staging/src/k8s.io/api/core/v1/types.go b/staging/src/k8s.io/api/core/v1/types.go index dc3ef561aa4..0d493467bad 100644 --- a/staging/src/k8s.io/api/core/v1/types.go +++ b/staging/src/k8s.io/api/core/v1/types.go @@ -5495,6 +5495,8 @@ type PodStatus struct { // by clients and scheduled onto hosts. // +k8s:supportsSubresource="/status" // +k8s:supportsSubresource="/ephemeralcontainers" +// +k8s:supportsSubresource="/resize" +// +k8s:supportsSubresource="/eviction" type Pod struct { metav1.TypeMeta `json:""` // Standard object's metadata. From 9b63de2453d0b018f9aed2c5bd6b5963f2aa58dd Mon Sep 17 00:00:00 2001 From: Yongrui Lin Date: Tue, 9 Jun 2026 20:50:15 +0000 Subject: [PATCH 04/10] extensions: disable declarative validation for v1beta1 extensions/v1beta1 is permanently unserved, and its pod-template workloads would otherwise force a forbidden staging -> k8s.io/kubernetes import. Disable validation-gen for the package. --- staging/src/k8s.io/api/extensions/v1beta1/doc.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/staging/src/k8s.io/api/extensions/v1beta1/doc.go b/staging/src/k8s.io/api/extensions/v1beta1/doc.go index bf39ca3e1e7..98ccb7685fd 100644 --- a/staging/src/k8s.io/api/extensions/v1beta1/doc.go +++ b/staging/src/k8s.io/api/extensions/v1beta1/doc.go @@ -19,7 +19,8 @@ limitations under the License. // +k8s:openapi-gen=true // +k8s:prerelease-lifecycle-gen=true // +k8s:openapi-model-package=io.k8s.api.extensions.v1beta1 -// +k8s:validation-gen=TypeMeta -// +k8s:validation-gen-input=k8s.io/api/extensions/v1beta1 +// extensions/v1beta1 is permanently unserved, so version-specific declarative +// validation here is unreachable. +// +k8s:validation-gen=false package v1beta1 From d1c82cbeb2e32d974dce6a9c27424e0a4fe0c0b3 Mon Sep 17 00:00:00 2001 From: Yongrui Lin Date: Tue, 9 Jun 2026 20:50:16 +0000 Subject: [PATCH 05/10] Regenerate validation code and protobuf for toleration migration Output of hack/update-codegen.sh. --- pkg/apis/apps/v1/zz_generated.validations.go | 374 ++++++++++++++++ .../apps/v1beta1/zz_generated.validations.go | 185 ++++++++ .../apps/v1beta2/zz_generated.validations.go | 355 +++++++++++++++ pkg/apis/batch/v1/zz_generated.validations.go | 26 +- pkg/apis/core/v1/zz_generated.validations.go | 291 +++++++++++- pkg/apis/node/v1/zz_generated.validations.go | 78 +++- .../node/v1alpha1/zz_generated.validations.go | 77 +++- .../node/v1beta1/zz_generated.validations.go | 78 +++- .../src/k8s.io/api/apps/v1/generated.proto | 3 + .../k8s.io/api/apps/v1beta1/generated.proto | 2 + .../k8s.io/api/apps/v1beta2/generated.proto | 3 + .../src/k8s.io/api/core/v1/generated.proto | 6 + .../v1beta1/zz_generated.validations.go | 418 ------------------ .../src/k8s.io/api/node/v1/generated.proto | 2 + .../k8s.io/api/node/v1alpha1/generated.proto | 2 + .../k8s.io/api/node/v1beta1/generated.proto | 2 + .../zz_generated.validations.main_test.go | 43 ++ .../zz_generated.validations.v1_test.go | 38 ++ .../zz_generated.validations.v1beta2_test.go | 38 ++ .../zz_generated.validations.main_test.go | 43 ++ .../zz_generated.validations.v1_test.go | 38 ++ .../zz_generated.validations.v1beta1_test.go | 38 ++ .../zz_generated.validations.v1beta2_test.go | 38 ++ .../zz_generated.validations.main_test.go | 43 ++ .../zz_generated.validations.v1_test.go | 38 ++ .../zz_generated.validations.v1beta2_test.go | 38 ++ .../zz_generated.validations.main_test.go | 43 ++ .../zz_generated.validations.v1_test.go | 38 ++ .../zz_generated.validations.v1beta1_test.go | 38 ++ .../zz_generated.validations.v1beta2_test.go | 38 ++ .../zz_generated.validations.v1_test.go | 3 + .../zz_generated.validations.v1beta1_test.go | 3 + .../job/zz_generated.validations.v1_test.go | 3 + .../pod/zz_generated.validations.main_test.go | 43 ++ .../pod/zz_generated.validations.v1_test.go | 38 ++ .../zz_generated.validations.main_test.go | 43 ++ .../zz_generated.validations.v1_test.go | 38 ++ .../zz_generated.validations.v1_test.go | 3 + .../zz_generated.validations.v1_test.go | 3 + .../zz_generated.validations.v1alpha1_test.go | 3 + .../zz_generated.validations.v1beta1_test.go | 3 + 41 files changed, 2214 insertions(+), 423 deletions(-) delete mode 100644 staging/src/k8s.io/api/extensions/v1beta1/zz_generated.validations.go create mode 100644 test/declarative_validation/apps/daemonset/zz_generated.validations.main_test.go create mode 100644 test/declarative_validation/apps/daemonset/zz_generated.validations.v1_test.go create mode 100644 test/declarative_validation/apps/daemonset/zz_generated.validations.v1beta2_test.go create mode 100644 test/declarative_validation/apps/deployment/zz_generated.validations.main_test.go create mode 100644 test/declarative_validation/apps/deployment/zz_generated.validations.v1_test.go create mode 100644 test/declarative_validation/apps/deployment/zz_generated.validations.v1beta1_test.go create mode 100644 test/declarative_validation/apps/deployment/zz_generated.validations.v1beta2_test.go create mode 100644 test/declarative_validation/apps/replicaset/zz_generated.validations.main_test.go create mode 100644 test/declarative_validation/apps/replicaset/zz_generated.validations.v1_test.go create mode 100644 test/declarative_validation/apps/replicaset/zz_generated.validations.v1beta2_test.go create mode 100644 test/declarative_validation/apps/statefulset/zz_generated.validations.main_test.go create mode 100644 test/declarative_validation/apps/statefulset/zz_generated.validations.v1_test.go create mode 100644 test/declarative_validation/apps/statefulset/zz_generated.validations.v1beta1_test.go create mode 100644 test/declarative_validation/apps/statefulset/zz_generated.validations.v1beta2_test.go create mode 100644 test/declarative_validation/core/pod/zz_generated.validations.main_test.go create mode 100644 test/declarative_validation/core/pod/zz_generated.validations.v1_test.go create mode 100644 test/declarative_validation/core/podtemplate/zz_generated.validations.main_test.go create mode 100644 test/declarative_validation/core/podtemplate/zz_generated.validations.v1_test.go diff --git a/pkg/apis/apps/v1/zz_generated.validations.go b/pkg/apis/apps/v1/zz_generated.validations.go index 61ebb8b5264..10a104a5617 100644 --- a/pkg/apis/apps/v1/zz_generated.validations.go +++ b/pkg/apis/apps/v1/zz_generated.validations.go @@ -20,3 +20,377 @@ limitations under the License. // Code generated by validation-gen. DO NOT EDIT. package v1 + +import ( + context "context" + fmt "fmt" + + appsv1 "k8s.io/api/apps/v1" + apicorev1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" + operation "k8s.io/apimachinery/pkg/api/operation" + safe "k8s.io/apimachinery/pkg/api/safe" + runtime "k8s.io/apimachinery/pkg/runtime" + field "k8s.io/apimachinery/pkg/util/validation/field" + corev1 "k8s.io/kubernetes/pkg/apis/core/v1" +) + +func init() { localSchemeBuilder.Register(RegisterValidations) } + +// RegisterValidations adds validation functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterValidations(scheme *runtime.Scheme) error { + // type DaemonSet + scheme.AddValidationFunc( + (*appsv1.DaemonSet)(nil), + func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/", "/status": + return Validate_DaemonSet( + ctx, op, nil, /* fldPath */ + obj.(*appsv1.DaemonSet), + safe.Cast[*appsv1.DaemonSet](oldObj)) + } + return field.ErrorList{ + field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), + } + }) + // type Deployment + scheme.AddValidationFunc( + (*appsv1.Deployment)(nil), + func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/", "/scale", "/status": + return Validate_Deployment( + ctx, op, nil, /* fldPath */ + obj.(*appsv1.Deployment), + safe.Cast[*appsv1.Deployment](oldObj)) + } + return field.ErrorList{ + field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), + } + }) + // type ReplicaSet + scheme.AddValidationFunc( + (*appsv1.ReplicaSet)(nil), + func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/", "/scale", "/status": + return Validate_ReplicaSet( + ctx, op, nil, /* fldPath */ + obj.(*appsv1.ReplicaSet), + safe.Cast[*appsv1.ReplicaSet](oldObj)) + } + return field.ErrorList{ + field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), + } + }) + // type StatefulSet + scheme.AddValidationFunc( + (*appsv1.StatefulSet)(nil), + func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/", "/scale", "/status": + return Validate_StatefulSet( + ctx, op, nil, /* fldPath */ + obj.(*appsv1.StatefulSet), + safe.Cast[*appsv1.StatefulSet](oldObj)) + } + return field.ErrorList{ + field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), + } + }) + return nil +} + +// Validate_DaemonSet validates an instance of DaemonSet according +// to declarative validation rules in the API schema. +func Validate_DaemonSet( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1.DaemonSet) (errs field.ErrorList) { + + // field appsv1.DaemonSet.TypeMeta has no validation + // field appsv1.DaemonSet.ObjectMeta has no validation + + { // field appsv1.DaemonSet.Spec + fn := func( + fldPath *field.Path, + obj, oldObj *appsv1.DaemonSetSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, Validate_DaemonSetSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1.DaemonSet) *appsv1.DaemonSetSpec { + return &oldObj.Spec + }) + errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) + } + + // field appsv1.DaemonSet.Status has no validation + return errs +} + +// Validate_DaemonSetSpec validates an instance of DaemonSetSpec according +// to declarative validation rules in the API schema. +func Validate_DaemonSetSpec( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1.DaemonSetSpec) (errs field.ErrorList) { + + // field appsv1.DaemonSetSpec.Selector has no validation + + { // field appsv1.DaemonSetSpec.Template + fn := func( + fldPath *field.Path, + obj, oldObj *apicorev1.PodTemplateSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, corev1.Validate_PodTemplateSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1.DaemonSetSpec) *apicorev1.PodTemplateSpec { + return &oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), &obj.Template, oldVal, oldObj != nil)...) + } + + // field appsv1.DaemonSetSpec.UpdateStrategy has no validation + // field appsv1.DaemonSetSpec.MinReadySeconds has no validation + // field appsv1.DaemonSetSpec.RevisionHistoryLimit has no validation + return errs +} + +// Validate_Deployment validates an instance of Deployment according +// to declarative validation rules in the API schema. +func Validate_Deployment( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1.Deployment) (errs field.ErrorList) { + + // field appsv1.Deployment.TypeMeta has no validation + // field appsv1.Deployment.ObjectMeta has no validation + + { // field appsv1.Deployment.Spec + fn := func( + fldPath *field.Path, + obj, oldObj *appsv1.DeploymentSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, Validate_DeploymentSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1.Deployment) *appsv1.DeploymentSpec { + return &oldObj.Spec + }) + errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) + } + + // field appsv1.Deployment.Status has no validation + return errs +} + +// Validate_DeploymentSpec validates an instance of DeploymentSpec according +// to declarative validation rules in the API schema. +func Validate_DeploymentSpec( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1.DeploymentSpec) (errs field.ErrorList) { + + // field appsv1.DeploymentSpec.Replicas has no validation + // field appsv1.DeploymentSpec.Selector has no validation + + { // field appsv1.DeploymentSpec.Template + fn := func( + fldPath *field.Path, + obj, oldObj *apicorev1.PodTemplateSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, corev1.Validate_PodTemplateSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1.DeploymentSpec) *apicorev1.PodTemplateSpec { + return &oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), &obj.Template, oldVal, oldObj != nil)...) + } + + // field appsv1.DeploymentSpec.Strategy has no validation + // field appsv1.DeploymentSpec.MinReadySeconds has no validation + // field appsv1.DeploymentSpec.RevisionHistoryLimit has no validation + // field appsv1.DeploymentSpec.Paused has no validation + // field appsv1.DeploymentSpec.ProgressDeadlineSeconds has no validation + return errs +} + +// Validate_ReplicaSet validates an instance of ReplicaSet according +// to declarative validation rules in the API schema. +func Validate_ReplicaSet( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1.ReplicaSet) (errs field.ErrorList) { + + // field appsv1.ReplicaSet.TypeMeta has no validation + // field appsv1.ReplicaSet.ObjectMeta has no validation + + { // field appsv1.ReplicaSet.Spec + fn := func( + fldPath *field.Path, + obj, oldObj *appsv1.ReplicaSetSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, Validate_ReplicaSetSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1.ReplicaSet) *appsv1.ReplicaSetSpec { + return &oldObj.Spec + }) + errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) + } + + // field appsv1.ReplicaSet.Status has no validation + return errs +} + +// Validate_ReplicaSetSpec validates an instance of ReplicaSetSpec according +// to declarative validation rules in the API schema. +func Validate_ReplicaSetSpec( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1.ReplicaSetSpec) (errs field.ErrorList) { + + // field appsv1.ReplicaSetSpec.Replicas has no validation + // field appsv1.ReplicaSetSpec.MinReadySeconds has no validation + // field appsv1.ReplicaSetSpec.Selector has no validation + + { // field appsv1.ReplicaSetSpec.Template + fn := func( + fldPath *field.Path, + obj, oldObj *apicorev1.PodTemplateSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, corev1.Validate_PodTemplateSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1.ReplicaSetSpec) *apicorev1.PodTemplateSpec { + return &oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), &obj.Template, oldVal, oldObj != nil)...) + } + + return errs +} + +// Validate_StatefulSet validates an instance of StatefulSet according +// to declarative validation rules in the API schema. +func Validate_StatefulSet( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1.StatefulSet) (errs field.ErrorList) { + + // field appsv1.StatefulSet.TypeMeta has no validation + // field appsv1.StatefulSet.ObjectMeta has no validation + + { // field appsv1.StatefulSet.Spec + fn := func( + fldPath *field.Path, + obj, oldObj *appsv1.StatefulSetSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, Validate_StatefulSetSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1.StatefulSet) *appsv1.StatefulSetSpec { + return &oldObj.Spec + }) + errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) + } + + // field appsv1.StatefulSet.Status has no validation + return errs +} + +// Validate_StatefulSetSpec validates an instance of StatefulSetSpec according +// to declarative validation rules in the API schema. +func Validate_StatefulSetSpec( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1.StatefulSetSpec) (errs field.ErrorList) { + + // field appsv1.StatefulSetSpec.Replicas has no validation + // field appsv1.StatefulSetSpec.Selector has no validation + + { // field appsv1.StatefulSetSpec.Template + fn := func( + fldPath *field.Path, + obj, oldObj *apicorev1.PodTemplateSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, corev1.Validate_PodTemplateSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1.StatefulSetSpec) *apicorev1.PodTemplateSpec { + return &oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), &obj.Template, oldVal, oldObj != nil)...) + } + + // field appsv1.StatefulSetSpec.VolumeClaimTemplates has no validation + // field appsv1.StatefulSetSpec.ServiceName has no validation + // field appsv1.StatefulSetSpec.PodManagementPolicy has no validation + // field appsv1.StatefulSetSpec.UpdateStrategy has no validation + // field appsv1.StatefulSetSpec.RevisionHistoryLimit has no validation + // field appsv1.StatefulSetSpec.MinReadySeconds has no validation + // field appsv1.StatefulSetSpec.PersistentVolumeClaimRetentionPolicy has no validation + // field appsv1.StatefulSetSpec.Ordinals has no validation + return errs +} diff --git a/pkg/apis/apps/v1beta1/zz_generated.validations.go b/pkg/apis/apps/v1beta1/zz_generated.validations.go index 225c87224ec..41bafcceb48 100644 --- a/pkg/apis/apps/v1beta1/zz_generated.validations.go +++ b/pkg/apis/apps/v1beta1/zz_generated.validations.go @@ -26,11 +26,14 @@ import ( fmt "fmt" appsv1beta1 "k8s.io/api/apps/v1beta1" + corev1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" operation "k8s.io/apimachinery/pkg/api/operation" safe "k8s.io/apimachinery/pkg/api/safe" validate "k8s.io/apimachinery/pkg/api/validate" runtime "k8s.io/apimachinery/pkg/runtime" field "k8s.io/apimachinery/pkg/util/validation/field" + v1 "k8s.io/kubernetes/pkg/apis/core/v1" ) func init() { localSchemeBuilder.Register(RegisterValidations) } @@ -38,6 +41,21 @@ func init() { localSchemeBuilder.Register(RegisterValidations) } // RegisterValidations adds validation functions to the given scheme. // Public to allow building arbitrary schemes. func RegisterValidations(scheme *runtime.Scheme) error { + // type Deployment + scheme.AddValidationFunc( + (*appsv1beta1.Deployment)(nil), + func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/", "/scale", "/status": + return Validate_Deployment( + ctx, op, nil, /* fldPath */ + obj.(*appsv1beta1.Deployment), + safe.Cast[*appsv1beta1.Deployment](oldObj)) + } + return field.ErrorList{ + field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), + } + }) // type Scale scheme.AddValidationFunc( (*appsv1beta1.Scale)(nil), @@ -53,9 +71,99 @@ func RegisterValidations(scheme *runtime.Scheme) error { field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), } }) + // type StatefulSet + scheme.AddValidationFunc( + (*appsv1beta1.StatefulSet)(nil), + func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/", "/scale", "/status": + return Validate_StatefulSet( + ctx, op, nil, /* fldPath */ + obj.(*appsv1beta1.StatefulSet), + safe.Cast[*appsv1beta1.StatefulSet](oldObj)) + } + return field.ErrorList{ + field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), + } + }) return nil } +// Validate_Deployment validates an instance of Deployment according +// to declarative validation rules in the API schema. +func Validate_Deployment( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1beta1.Deployment) (errs field.ErrorList) { + + // field appsv1beta1.Deployment.TypeMeta has no validation + // field appsv1beta1.Deployment.ObjectMeta has no validation + + { // field appsv1beta1.Deployment.Spec + fn := func( + fldPath *field.Path, + obj, oldObj *appsv1beta1.DeploymentSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, Validate_DeploymentSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1beta1.Deployment) *appsv1beta1.DeploymentSpec { + return &oldObj.Spec + }) + errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) + } + + // field appsv1beta1.Deployment.Status has no validation + return errs +} + +// Validate_DeploymentSpec validates an instance of DeploymentSpec according +// to declarative validation rules in the API schema. +func Validate_DeploymentSpec( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1beta1.DeploymentSpec) (errs field.ErrorList) { + + // field appsv1beta1.DeploymentSpec.Replicas has no validation + // field appsv1beta1.DeploymentSpec.Selector has no validation + + { // field appsv1beta1.DeploymentSpec.Template + fn := func( + fldPath *field.Path, + obj, oldObj *corev1.PodTemplateSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, v1.Validate_PodTemplateSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1beta1.DeploymentSpec) *corev1.PodTemplateSpec { + return &oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), &obj.Template, oldVal, oldObj != nil)...) + } + + // field appsv1beta1.DeploymentSpec.Strategy has no validation + // field appsv1beta1.DeploymentSpec.MinReadySeconds has no validation + // field appsv1beta1.DeploymentSpec.RevisionHistoryLimit has no validation + // field appsv1beta1.DeploymentSpec.Paused has no validation + // field appsv1beta1.DeploymentSpec.RollbackTo has no validation + // field appsv1beta1.DeploymentSpec.ProgressDeadlineSeconds has no validation + return errs +} + // Validate_Scale validates an instance of Scale according // to declarative validation rules in the API schema. func Validate_Scale( @@ -124,3 +232,80 @@ func Validate_ScaleSpec( return errs } + +// Validate_StatefulSet validates an instance of StatefulSet according +// to declarative validation rules in the API schema. +func Validate_StatefulSet( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1beta1.StatefulSet) (errs field.ErrorList) { + + // field appsv1beta1.StatefulSet.TypeMeta has no validation + // field appsv1beta1.StatefulSet.ObjectMeta has no validation + + { // field appsv1beta1.StatefulSet.Spec + fn := func( + fldPath *field.Path, + obj, oldObj *appsv1beta1.StatefulSetSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, Validate_StatefulSetSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1beta1.StatefulSet) *appsv1beta1.StatefulSetSpec { + return &oldObj.Spec + }) + errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) + } + + // field appsv1beta1.StatefulSet.Status has no validation + return errs +} + +// Validate_StatefulSetSpec validates an instance of StatefulSetSpec according +// to declarative validation rules in the API schema. +func Validate_StatefulSetSpec( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1beta1.StatefulSetSpec) (errs field.ErrorList) { + + // field appsv1beta1.StatefulSetSpec.Replicas has no validation + // field appsv1beta1.StatefulSetSpec.Selector has no validation + + { // field appsv1beta1.StatefulSetSpec.Template + fn := func( + fldPath *field.Path, + obj, oldObj *corev1.PodTemplateSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, v1.Validate_PodTemplateSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1beta1.StatefulSetSpec) *corev1.PodTemplateSpec { + return &oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), &obj.Template, oldVal, oldObj != nil)...) + } + + // field appsv1beta1.StatefulSetSpec.VolumeClaimTemplates has no validation + // field appsv1beta1.StatefulSetSpec.ServiceName has no validation + // field appsv1beta1.StatefulSetSpec.PodManagementPolicy has no validation + // field appsv1beta1.StatefulSetSpec.UpdateStrategy has no validation + // field appsv1beta1.StatefulSetSpec.RevisionHistoryLimit has no validation + // field appsv1beta1.StatefulSetSpec.MinReadySeconds has no validation + // field appsv1beta1.StatefulSetSpec.PersistentVolumeClaimRetentionPolicy has no validation + // field appsv1beta1.StatefulSetSpec.Ordinals has no validation + return errs +} diff --git a/pkg/apis/apps/v1beta2/zz_generated.validations.go b/pkg/apis/apps/v1beta2/zz_generated.validations.go index 5eee63c7dde..224bce505a3 100644 --- a/pkg/apis/apps/v1beta2/zz_generated.validations.go +++ b/pkg/apis/apps/v1beta2/zz_generated.validations.go @@ -26,11 +26,14 @@ import ( fmt "fmt" appsv1beta2 "k8s.io/api/apps/v1beta2" + corev1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" operation "k8s.io/apimachinery/pkg/api/operation" safe "k8s.io/apimachinery/pkg/api/safe" validate "k8s.io/apimachinery/pkg/api/validate" runtime "k8s.io/apimachinery/pkg/runtime" field "k8s.io/apimachinery/pkg/util/validation/field" + v1 "k8s.io/kubernetes/pkg/apis/core/v1" ) func init() { localSchemeBuilder.Register(RegisterValidations) } @@ -38,6 +41,51 @@ func init() { localSchemeBuilder.Register(RegisterValidations) } // RegisterValidations adds validation functions to the given scheme. // Public to allow building arbitrary schemes. func RegisterValidations(scheme *runtime.Scheme) error { + // type DaemonSet + scheme.AddValidationFunc( + (*appsv1beta2.DaemonSet)(nil), + func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/", "/status": + return Validate_DaemonSet( + ctx, op, nil, /* fldPath */ + obj.(*appsv1beta2.DaemonSet), + safe.Cast[*appsv1beta2.DaemonSet](oldObj)) + } + return field.ErrorList{ + field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), + } + }) + // type Deployment + scheme.AddValidationFunc( + (*appsv1beta2.Deployment)(nil), + func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/", "/scale", "/status": + return Validate_Deployment( + ctx, op, nil, /* fldPath */ + obj.(*appsv1beta2.Deployment), + safe.Cast[*appsv1beta2.Deployment](oldObj)) + } + return field.ErrorList{ + field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), + } + }) + // type ReplicaSet + scheme.AddValidationFunc( + (*appsv1beta2.ReplicaSet)(nil), + func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/", "/scale", "/status": + return Validate_ReplicaSet( + ctx, op, nil, /* fldPath */ + obj.(*appsv1beta2.ReplicaSet), + safe.Cast[*appsv1beta2.ReplicaSet](oldObj)) + } + return field.ErrorList{ + field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), + } + }) // type Scale scheme.AddValidationFunc( (*appsv1beta2.Scale)(nil), @@ -53,9 +101,239 @@ func RegisterValidations(scheme *runtime.Scheme) error { field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), } }) + // type StatefulSet + scheme.AddValidationFunc( + (*appsv1beta2.StatefulSet)(nil), + func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/", "/scale", "/status": + return Validate_StatefulSet( + ctx, op, nil, /* fldPath */ + obj.(*appsv1beta2.StatefulSet), + safe.Cast[*appsv1beta2.StatefulSet](oldObj)) + } + return field.ErrorList{ + field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), + } + }) return nil } +// Validate_DaemonSet validates an instance of DaemonSet according +// to declarative validation rules in the API schema. +func Validate_DaemonSet( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1beta2.DaemonSet) (errs field.ErrorList) { + + // field appsv1beta2.DaemonSet.TypeMeta has no validation + // field appsv1beta2.DaemonSet.ObjectMeta has no validation + + { // field appsv1beta2.DaemonSet.Spec + fn := func( + fldPath *field.Path, + obj, oldObj *appsv1beta2.DaemonSetSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, Validate_DaemonSetSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1beta2.DaemonSet) *appsv1beta2.DaemonSetSpec { + return &oldObj.Spec + }) + errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) + } + + // field appsv1beta2.DaemonSet.Status has no validation + return errs +} + +// Validate_DaemonSetSpec validates an instance of DaemonSetSpec according +// to declarative validation rules in the API schema. +func Validate_DaemonSetSpec( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1beta2.DaemonSetSpec) (errs field.ErrorList) { + + // field appsv1beta2.DaemonSetSpec.Selector has no validation + + { // field appsv1beta2.DaemonSetSpec.Template + fn := func( + fldPath *field.Path, + obj, oldObj *corev1.PodTemplateSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, v1.Validate_PodTemplateSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1beta2.DaemonSetSpec) *corev1.PodTemplateSpec { + return &oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), &obj.Template, oldVal, oldObj != nil)...) + } + + // field appsv1beta2.DaemonSetSpec.UpdateStrategy has no validation + // field appsv1beta2.DaemonSetSpec.MinReadySeconds has no validation + // field appsv1beta2.DaemonSetSpec.RevisionHistoryLimit has no validation + return errs +} + +// Validate_Deployment validates an instance of Deployment according +// to declarative validation rules in the API schema. +func Validate_Deployment( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1beta2.Deployment) (errs field.ErrorList) { + + // field appsv1beta2.Deployment.TypeMeta has no validation + // field appsv1beta2.Deployment.ObjectMeta has no validation + + { // field appsv1beta2.Deployment.Spec + fn := func( + fldPath *field.Path, + obj, oldObj *appsv1beta2.DeploymentSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, Validate_DeploymentSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1beta2.Deployment) *appsv1beta2.DeploymentSpec { + return &oldObj.Spec + }) + errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) + } + + // field appsv1beta2.Deployment.Status has no validation + return errs +} + +// Validate_DeploymentSpec validates an instance of DeploymentSpec according +// to declarative validation rules in the API schema. +func Validate_DeploymentSpec( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1beta2.DeploymentSpec) (errs field.ErrorList) { + + // field appsv1beta2.DeploymentSpec.Replicas has no validation + // field appsv1beta2.DeploymentSpec.Selector has no validation + + { // field appsv1beta2.DeploymentSpec.Template + fn := func( + fldPath *field.Path, + obj, oldObj *corev1.PodTemplateSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, v1.Validate_PodTemplateSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1beta2.DeploymentSpec) *corev1.PodTemplateSpec { + return &oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), &obj.Template, oldVal, oldObj != nil)...) + } + + // field appsv1beta2.DeploymentSpec.Strategy has no validation + // field appsv1beta2.DeploymentSpec.MinReadySeconds has no validation + // field appsv1beta2.DeploymentSpec.RevisionHistoryLimit has no validation + // field appsv1beta2.DeploymentSpec.Paused has no validation + // field appsv1beta2.DeploymentSpec.ProgressDeadlineSeconds has no validation + return errs +} + +// Validate_ReplicaSet validates an instance of ReplicaSet according +// to declarative validation rules in the API schema. +func Validate_ReplicaSet( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1beta2.ReplicaSet) (errs field.ErrorList) { + + // field appsv1beta2.ReplicaSet.TypeMeta has no validation + // field appsv1beta2.ReplicaSet.ObjectMeta has no validation + + { // field appsv1beta2.ReplicaSet.Spec + fn := func( + fldPath *field.Path, + obj, oldObj *appsv1beta2.ReplicaSetSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, Validate_ReplicaSetSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1beta2.ReplicaSet) *appsv1beta2.ReplicaSetSpec { + return &oldObj.Spec + }) + errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) + } + + // field appsv1beta2.ReplicaSet.Status has no validation + return errs +} + +// Validate_ReplicaSetSpec validates an instance of ReplicaSetSpec according +// to declarative validation rules in the API schema. +func Validate_ReplicaSetSpec( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1beta2.ReplicaSetSpec) (errs field.ErrorList) { + + // field appsv1beta2.ReplicaSetSpec.Replicas has no validation + // field appsv1beta2.ReplicaSetSpec.MinReadySeconds has no validation + // field appsv1beta2.ReplicaSetSpec.Selector has no validation + + { // field appsv1beta2.ReplicaSetSpec.Template + fn := func( + fldPath *field.Path, + obj, oldObj *corev1.PodTemplateSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, v1.Validate_PodTemplateSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1beta2.ReplicaSetSpec) *corev1.PodTemplateSpec { + return &oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), &obj.Template, oldVal, oldObj != nil)...) + } + + return errs +} + // Validate_Scale validates an instance of Scale according // to declarative validation rules in the API schema. func Validate_Scale( @@ -124,3 +402,80 @@ func Validate_ScaleSpec( return errs } + +// Validate_StatefulSet validates an instance of StatefulSet according +// to declarative validation rules in the API schema. +func Validate_StatefulSet( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1beta2.StatefulSet) (errs field.ErrorList) { + + // field appsv1beta2.StatefulSet.TypeMeta has no validation + // field appsv1beta2.StatefulSet.ObjectMeta has no validation + + { // field appsv1beta2.StatefulSet.Spec + fn := func( + fldPath *field.Path, + obj, oldObj *appsv1beta2.StatefulSetSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, Validate_StatefulSetSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1beta2.StatefulSet) *appsv1beta2.StatefulSetSpec { + return &oldObj.Spec + }) + errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) + } + + // field appsv1beta2.StatefulSet.Status has no validation + return errs +} + +// Validate_StatefulSetSpec validates an instance of StatefulSetSpec according +// to declarative validation rules in the API schema. +func Validate_StatefulSetSpec( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *appsv1beta2.StatefulSetSpec) (errs field.ErrorList) { + + // field appsv1beta2.StatefulSetSpec.Replicas has no validation + // field appsv1beta2.StatefulSetSpec.Selector has no validation + + { // field appsv1beta2.StatefulSetSpec.Template + fn := func( + fldPath *field.Path, + obj, oldObj *corev1.PodTemplateSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, v1.Validate_PodTemplateSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *appsv1beta2.StatefulSetSpec) *corev1.PodTemplateSpec { + return &oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), &obj.Template, oldVal, oldObj != nil)...) + } + + // field appsv1beta2.StatefulSetSpec.VolumeClaimTemplates has no validation + // field appsv1beta2.StatefulSetSpec.ServiceName has no validation + // field appsv1beta2.StatefulSetSpec.PodManagementPolicy has no validation + // field appsv1beta2.StatefulSetSpec.UpdateStrategy has no validation + // field appsv1beta2.StatefulSetSpec.RevisionHistoryLimit has no validation + // field appsv1beta2.StatefulSetSpec.MinReadySeconds has no validation + // field appsv1beta2.StatefulSetSpec.PersistentVolumeClaimRetentionPolicy has no validation + // field appsv1beta2.StatefulSetSpec.Ordinals has no validation + return errs +} diff --git a/pkg/apis/batch/v1/zz_generated.validations.go b/pkg/apis/batch/v1/zz_generated.validations.go index 9d6fb185306..b904ed0f10e 100644 --- a/pkg/apis/batch/v1/zz_generated.validations.go +++ b/pkg/apis/batch/v1/zz_generated.validations.go @@ -26,12 +26,14 @@ import ( fmt "fmt" batchv1 "k8s.io/api/batch/v1" + apicorev1 "k8s.io/api/core/v1" equality "k8s.io/apimachinery/pkg/api/equality" operation "k8s.io/apimachinery/pkg/api/operation" safe "k8s.io/apimachinery/pkg/api/safe" validate "k8s.io/apimachinery/pkg/api/validate" runtime "k8s.io/apimachinery/pkg/runtime" field "k8s.io/apimachinery/pkg/util/validation/field" + corev1 "k8s.io/kubernetes/pkg/apis/core/v1" ) func init() { localSchemeBuilder.Register(RegisterValidations) } @@ -269,7 +271,29 @@ func Validate_JobSpec( // field batchv1.JobSpec.Selector has no validation // field batchv1.JobSpec.ManualSelector has no validation - // field batchv1.JobSpec.Template has no validation + + { // field batchv1.JobSpec.Template + fn := func( + fldPath *field.Path, + obj, oldObj *apicorev1.PodTemplateSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, corev1.Validate_PodTemplateSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *batchv1.JobSpec) *apicorev1.PodTemplateSpec { + return &oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), &obj.Template, oldVal, oldObj != nil)...) + } + // field batchv1.JobSpec.TTLSecondsAfterFinished has no validation // field batchv1.JobSpec.CompletionMode has no validation // field batchv1.JobSpec.Suspend has no validation diff --git a/pkg/apis/core/v1/zz_generated.validations.go b/pkg/apis/core/v1/zz_generated.validations.go index 90baa118c85..311112d9564 100644 --- a/pkg/apis/core/v1/zz_generated.validations.go +++ b/pkg/apis/core/v1/zz_generated.validations.go @@ -40,6 +40,36 @@ func init() { localSchemeBuilder.Register(RegisterValidations) } // RegisterValidations adds validation functions to the given scheme. // Public to allow building arbitrary schemes. func RegisterValidations(scheme *runtime.Scheme) error { + // type Pod + scheme.AddValidationFunc( + (*corev1.Pod)(nil), + func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/", "/ephemeralcontainers", "/eviction", "/resize", "/status": + return Validate_Pod( + ctx, op, nil, /* fldPath */ + obj.(*corev1.Pod), + safe.Cast[*corev1.Pod](oldObj)) + } + return field.ErrorList{ + field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), + } + }) + // type PodTemplate + scheme.AddValidationFunc( + (*corev1.PodTemplate)(nil), + func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { + switch op.Request.SubresourcePath() { + case "/": + return Validate_PodTemplate( + ctx, op, nil, /* fldPath */ + obj.(*corev1.PodTemplate), + safe.Cast[*corev1.PodTemplate](oldObj)) + } + return field.ErrorList{ + field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), + } + }) // type ReplicationController scheme.AddValidationFunc( (*corev1.ReplicationController)(nil), @@ -73,6 +103,191 @@ func RegisterValidations(scheme *runtime.Scheme) error { return nil } +// Validate_Pod validates an instance of Pod according +// to declarative validation rules in the API schema. +func Validate_Pod( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *corev1.Pod) (errs field.ErrorList) { + + // field corev1.Pod.TypeMeta has no validation + // field corev1.Pod.ObjectMeta has no validation + + { // field corev1.Pod.Spec + fn := func( + fldPath *field.Path, + obj, oldObj *corev1.PodSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, Validate_PodSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *corev1.Pod) *corev1.PodSpec { + return &oldObj.Spec + }) + errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) + } + + // field corev1.Pod.Status has no validation + return errs +} + +// Validate_PodSpec validates an instance of PodSpec according +// to declarative validation rules in the API schema. +func Validate_PodSpec( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *corev1.PodSpec) (errs field.ErrorList) { + + // field corev1.PodSpec.Volumes has no validation + // field corev1.PodSpec.InitContainers has no validation + // field corev1.PodSpec.Containers has no validation + // field corev1.PodSpec.EphemeralContainers has no validation + // field corev1.PodSpec.RestartPolicy has no validation + // field corev1.PodSpec.TerminationGracePeriodSeconds has no validation + // field corev1.PodSpec.ActiveDeadlineSeconds has no validation + // field corev1.PodSpec.DNSPolicy has no validation + // field corev1.PodSpec.NodeSelector has no validation + // field corev1.PodSpec.ServiceAccountName has no validation + // field corev1.PodSpec.DeprecatedServiceAccount has no validation + // field corev1.PodSpec.AutomountServiceAccountToken has no validation + // field corev1.PodSpec.NodeName has no validation + // field corev1.PodSpec.HostNetwork has no validation + // field corev1.PodSpec.HostPID has no validation + // field corev1.PodSpec.HostIPC has no validation + // field corev1.PodSpec.ShareProcessNamespace has no validation + // field corev1.PodSpec.SecurityContext has no validation + // field corev1.PodSpec.ImagePullSecrets has no validation + // field corev1.PodSpec.Hostname has no validation + // field corev1.PodSpec.Subdomain has no validation + // field corev1.PodSpec.Affinity has no validation + // field corev1.PodSpec.SchedulerName has no validation + + { // field corev1.PodSpec.Tolerations + fn := func( + fldPath *field.Path, + obj, oldObj []corev1.Toleration, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // iterate the list and call the type's validation function + if e := validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_Toleration); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *corev1.PodSpec) []corev1.Toleration { + return oldObj.Tolerations + }) + errs = append(errs, fn(fldPath.Child("tolerations"), obj.Tolerations, oldVal, oldObj != nil)...) + } + + // field corev1.PodSpec.HostAliases has no validation + // field corev1.PodSpec.PriorityClassName has no validation + // field corev1.PodSpec.Priority has no validation + // field corev1.PodSpec.DNSConfig has no validation + // field corev1.PodSpec.ReadinessGates has no validation + // field corev1.PodSpec.RuntimeClassName has no validation + // field corev1.PodSpec.EnableServiceLinks has no validation + // field corev1.PodSpec.PreemptionPolicy has no validation + // field corev1.PodSpec.Overhead has no validation + // field corev1.PodSpec.TopologySpreadConstraints has no validation + // field corev1.PodSpec.SetHostnameAsFQDN has no validation + // field corev1.PodSpec.OS has no validation + // field corev1.PodSpec.HostUsers has no validation + // field corev1.PodSpec.SchedulingGates has no validation + // field corev1.PodSpec.ResourceClaims has no validation + // field corev1.PodSpec.Resources has no validation + // field corev1.PodSpec.HostnameOverride has no validation + // field corev1.PodSpec.SchedulingGroup has no validation + return errs +} + +// Validate_PodTemplate validates an instance of PodTemplate according +// to declarative validation rules in the API schema. +func Validate_PodTemplate( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *corev1.PodTemplate) (errs field.ErrorList) { + + // field corev1.PodTemplate.TypeMeta has no validation + // field corev1.PodTemplate.ObjectMeta has no validation + + { // field corev1.PodTemplate.Template + fn := func( + fldPath *field.Path, + obj, oldObj *corev1.PodTemplateSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, Validate_PodTemplateSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *corev1.PodTemplate) *corev1.PodTemplateSpec { + return &oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), &obj.Template, oldVal, oldObj != nil)...) + } + + return errs +} + +// Validate_PodTemplateSpec validates an instance of PodTemplateSpec according +// to declarative validation rules in the API schema. +func Validate_PodTemplateSpec( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *corev1.PodTemplateSpec) (errs field.ErrorList) { + + // field corev1.PodTemplateSpec.ObjectMeta has no validation + + { // field corev1.PodTemplateSpec.Spec + fn := func( + fldPath *field.Path, + obj, oldObj *corev1.PodSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call the type's validation function + errs = append(errs, Validate_PodSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *corev1.PodTemplateSpec) *corev1.PodSpec { + return &oldObj.Spec + }) + errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) + } + + return errs +} + // Validate_ReplicationController validates an instance of ReplicationController according // to declarative validation rules in the API schema. func Validate_ReplicationController( @@ -207,7 +422,37 @@ func Validate_ReplicationControllerSpec( } // field corev1.ReplicationControllerSpec.Selector has no validation - // field corev1.ReplicationControllerSpec.Template has no validation + + { // field corev1.ReplicationControllerSpec.Template + fn := func( + fldPath *field.Path, + obj, oldObj *corev1.PodTemplateSpec, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // call the type's validation function + errs = append(errs, Validate_PodTemplateSpec(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *corev1.ReplicationControllerSpec) *corev1.PodTemplateSpec { + return oldObj.Template + }) + errs = append(errs, fn(fldPath.Child("template"), obj.Template, oldVal, oldObj != nil)...) + } + return errs } @@ -257,3 +502,47 @@ func Validate_Secret( return errs } + +// Validate_Toleration validates an instance of Toleration according +// to declarative validation rules in the API schema. +func Validate_Toleration( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *corev1.Toleration) (errs field.ErrorList) { + + { // field corev1.Toleration.Key + fn := func( + fldPath *field.Path, + obj, oldObj *string, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalValue(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + if e := validate.LabelKey(ctx, op, fldPath, obj, oldObj).MarkAlpha(); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *corev1.Toleration) *string { + return &oldObj.Key + }) + errs = append(errs, fn(fldPath.Child("key"), &obj.Key, oldVal, oldObj != nil)...) + } + + // field corev1.Toleration.Operator has no validation + // field corev1.Toleration.Value has no validation + // field corev1.Toleration.Effect has no validation + // field corev1.Toleration.TolerationSeconds has no validation + return errs +} diff --git a/pkg/apis/node/v1/zz_generated.validations.go b/pkg/apis/node/v1/zz_generated.validations.go index cf0a39420de..acfd3c2cf3a 100644 --- a/pkg/apis/node/v1/zz_generated.validations.go +++ b/pkg/apis/node/v1/zz_generated.validations.go @@ -25,12 +25,15 @@ import ( context "context" fmt "fmt" + apicorev1 "k8s.io/api/core/v1" nodev1 "k8s.io/api/node/v1" + equality "k8s.io/apimachinery/pkg/api/equality" operation "k8s.io/apimachinery/pkg/api/operation" safe "k8s.io/apimachinery/pkg/api/safe" validate "k8s.io/apimachinery/pkg/api/validate" runtime "k8s.io/apimachinery/pkg/runtime" field "k8s.io/apimachinery/pkg/util/validation/field" + corev1 "k8s.io/kubernetes/pkg/apis/core/v1" ) func init() { localSchemeBuilder.Register(RegisterValidations) } @@ -102,6 +105,79 @@ func Validate_RuntimeClass( } // field nodev1.RuntimeClass.Overhead has no validation - // field nodev1.RuntimeClass.Scheduling has no validation + + { // field nodev1.RuntimeClass.Scheduling + fn := func( + fldPath *field.Path, + obj, oldObj *nodev1.Scheduling, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // call the type's validation function + errs = append(errs, Validate_Scheduling(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *nodev1.RuntimeClass) *nodev1.Scheduling { + return oldObj.Scheduling + }) + errs = append(errs, fn(fldPath.Child("scheduling"), obj.Scheduling, oldVal, oldObj != nil)...) + } + + return errs +} + +// Validate_Scheduling validates an instance of Scheduling according +// to declarative validation rules in the API schema. +func Validate_Scheduling( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *nodev1.Scheduling) (errs field.ErrorList) { + + // field nodev1.Scheduling.NodeSelector has no validation + + { // field nodev1.Scheduling.Tolerations + fn := func( + fldPath *field.Path, + obj, oldObj []apicorev1.Toleration, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // iterate the list and call the type's validation function + if e := validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, corev1.Validate_Toleration); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *nodev1.Scheduling) []apicorev1.Toleration { + return oldObj.Tolerations + }) + errs = append(errs, fn(fldPath.Child("tolerations"), obj.Tolerations, oldVal, oldObj != nil)...) + } + return errs } diff --git a/pkg/apis/node/v1alpha1/zz_generated.validations.go b/pkg/apis/node/v1alpha1/zz_generated.validations.go index 0b55be8df5b..54e3c31d38b 100644 --- a/pkg/apis/node/v1alpha1/zz_generated.validations.go +++ b/pkg/apis/node/v1alpha1/zz_generated.validations.go @@ -25,6 +25,7 @@ import ( context "context" fmt "fmt" + corev1 "k8s.io/api/core/v1" nodev1alpha1 "k8s.io/api/node/v1alpha1" equality "k8s.io/apimachinery/pkg/api/equality" operation "k8s.io/apimachinery/pkg/api/operation" @@ -32,6 +33,7 @@ import ( validate "k8s.io/apimachinery/pkg/api/validate" runtime "k8s.io/apimachinery/pkg/runtime" field "k8s.io/apimachinery/pkg/util/validation/field" + v1 "k8s.io/kubernetes/pkg/apis/core/v1" ) func init() { localSchemeBuilder.Register(RegisterValidations) } @@ -134,6 +136,79 @@ func Validate_RuntimeClassSpec( } // field nodev1alpha1.RuntimeClassSpec.Overhead has no validation - // field nodev1alpha1.RuntimeClassSpec.Scheduling has no validation + + { // field nodev1alpha1.RuntimeClassSpec.Scheduling + fn := func( + fldPath *field.Path, + obj, oldObj *nodev1alpha1.Scheduling, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // call the type's validation function + errs = append(errs, Validate_Scheduling(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *nodev1alpha1.RuntimeClassSpec) *nodev1alpha1.Scheduling { + return oldObj.Scheduling + }) + errs = append(errs, fn(fldPath.Child("scheduling"), obj.Scheduling, oldVal, oldObj != nil)...) + } + + return errs +} + +// Validate_Scheduling validates an instance of Scheduling according +// to declarative validation rules in the API schema. +func Validate_Scheduling( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *nodev1alpha1.Scheduling) (errs field.ErrorList) { + + // field nodev1alpha1.Scheduling.NodeSelector has no validation + + { // field nodev1alpha1.Scheduling.Tolerations + fn := func( + fldPath *field.Path, + obj, oldObj []corev1.Toleration, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // iterate the list and call the type's validation function + if e := validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, v1.Validate_Toleration); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *nodev1alpha1.Scheduling) []corev1.Toleration { + return oldObj.Tolerations + }) + errs = append(errs, fn(fldPath.Child("tolerations"), obj.Tolerations, oldVal, oldObj != nil)...) + } + return errs } diff --git a/pkg/apis/node/v1beta1/zz_generated.validations.go b/pkg/apis/node/v1beta1/zz_generated.validations.go index e1aad5abd0d..a9cf134f1cd 100644 --- a/pkg/apis/node/v1beta1/zz_generated.validations.go +++ b/pkg/apis/node/v1beta1/zz_generated.validations.go @@ -25,12 +25,15 @@ import ( context "context" fmt "fmt" + corev1 "k8s.io/api/core/v1" nodev1beta1 "k8s.io/api/node/v1beta1" + equality "k8s.io/apimachinery/pkg/api/equality" operation "k8s.io/apimachinery/pkg/api/operation" safe "k8s.io/apimachinery/pkg/api/safe" validate "k8s.io/apimachinery/pkg/api/validate" runtime "k8s.io/apimachinery/pkg/runtime" field "k8s.io/apimachinery/pkg/util/validation/field" + v1 "k8s.io/kubernetes/pkg/apis/core/v1" ) func init() { localSchemeBuilder.Register(RegisterValidations) } @@ -102,6 +105,79 @@ func Validate_RuntimeClass( } // field nodev1beta1.RuntimeClass.Overhead has no validation - // field nodev1beta1.RuntimeClass.Scheduling has no validation + + { // field nodev1beta1.RuntimeClass.Scheduling + fn := func( + fldPath *field.Path, + obj, oldObj *nodev1beta1.Scheduling, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // call the type's validation function + errs = append(errs, Validate_Scheduling(ctx, op, fldPath, obj, oldObj)...) + return + } + oldVal := safe.Field(oldObj, + func(oldObj *nodev1beta1.RuntimeClass) *nodev1beta1.Scheduling { + return oldObj.Scheduling + }) + errs = append(errs, fn(fldPath.Child("scheduling"), obj.Scheduling, oldVal, oldObj != nil)...) + } + + return errs +} + +// Validate_Scheduling validates an instance of Scheduling according +// to declarative validation rules in the API schema. +func Validate_Scheduling( + ctx context.Context, op operation.Operation, fldPath *field.Path, + obj, oldObj *nodev1beta1.Scheduling) (errs field.ErrorList) { + + // field nodev1beta1.Scheduling.NodeSelector has no validation + + { // field nodev1beta1.Scheduling.Tolerations + fn := func( + fldPath *field.Path, + obj, oldObj []corev1.Toleration, + oldValueCorrelated bool) (errs field.ErrorList) { + // don't revalidate unchanged data + if oldValueCorrelated && op.Type == operation.Update { + if equality.Semantic.DeepEqual(obj, oldObj) { + return nil + } + } + // call field-attached validations + earlyReturn := false + if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { + earlyReturn = true + } + if earlyReturn { + return // do not proceed + } + // iterate the list and call the type's validation function + if e := validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, v1.Validate_Toleration); len(e) != 0 { + errs = append(errs, e...) + } + return + } + oldVal := safe.Field(oldObj, + func(oldObj *nodev1beta1.Scheduling) []corev1.Toleration { + return oldObj.Tolerations + }) + errs = append(errs, fn(fldPath.Child("tolerations"), obj.Tolerations, oldVal, oldObj != nil)...) + } + return errs } diff --git a/staging/src/k8s.io/api/apps/v1/generated.proto b/staging/src/k8s.io/api/apps/v1/generated.proto index ee7b2099e65..c683cec3efc 100644 --- a/staging/src/k8s.io/api/apps/v1/generated.proto +++ b/staging/src/k8s.io/api/apps/v1/generated.proto @@ -228,6 +228,7 @@ message DaemonSetUpdateStrategy { } // Deployment enables declarative updates for Pods and ReplicaSets. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" message Deployment { // Standard object's metadata. @@ -394,6 +395,7 @@ message DeploymentStrategy { } // ReplicaSet ensures that a specified number of pod replicas are running at any given time. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" message ReplicaSet { // If the Labels of a ReplicaSet are empty, they are defaulted to @@ -619,6 +621,7 @@ message RollingUpdateStatefulSetStrategy { // // The StatefulSet guarantees that a given network identity will always // map to the same storage identity. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" message StatefulSet { // Standard object's metadata. diff --git a/staging/src/k8s.io/api/apps/v1beta1/generated.proto b/staging/src/k8s.io/api/apps/v1beta1/generated.proto index a79358857e1..6e7ba3fe31d 100644 --- a/staging/src/k8s.io/api/apps/v1beta1/generated.proto +++ b/staging/src/k8s.io/api/apps/v1beta1/generated.proto @@ -69,6 +69,7 @@ message ControllerRevisionList { // DEPRECATED - This group version of Deployment is deprecated by apps/v1beta2/Deployment. See the release notes for // more information. // Deployment enables declarative updates for Pods and ReplicaSets. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" message Deployment { // Standard object metadata. @@ -366,6 +367,7 @@ message ScaleStatus { // // The StatefulSet guarantees that a given network identity will always // map to the same storage identity. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" message StatefulSet { // +optional diff --git a/staging/src/k8s.io/api/apps/v1beta2/generated.proto b/staging/src/k8s.io/api/apps/v1beta2/generated.proto index df31e0fee17..5d203ac9379 100644 --- a/staging/src/k8s.io/api/apps/v1beta2/generated.proto +++ b/staging/src/k8s.io/api/apps/v1beta2/generated.proto @@ -234,6 +234,7 @@ message DaemonSetUpdateStrategy { // DEPRECATED - This group version of Deployment is deprecated by apps/v1/Deployment. See the release notes for // more information. // Deployment enables declarative updates for Pods and ReplicaSets. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" message Deployment { // Standard object metadata. @@ -401,6 +402,7 @@ message DeploymentStrategy { // DEPRECATED - This group version of ReplicaSet is deprecated by apps/v1/ReplicaSet. See the release notes for // more information. // ReplicaSet ensures that a specified number of pod replicas are running at any given time. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" message ReplicaSet { // If the Labels of a ReplicaSet are empty, they are defaulted to @@ -673,6 +675,7 @@ message ScaleStatus { // // The StatefulSet guarantees that a given network identity will always // map to the same storage identity. +// +k8s:supportsSubresource="/scale" // +k8s:supportsSubresource="/status" message StatefulSet { // +optional diff --git a/staging/src/k8s.io/api/core/v1/generated.proto b/staging/src/k8s.io/api/core/v1/generated.proto index 263a1599cb1..81433285f4a 100644 --- a/staging/src/k8s.io/api/core/v1/generated.proto +++ b/staging/src/k8s.io/api/core/v1/generated.proto @@ -3686,6 +3686,8 @@ message PhotonPersistentDiskVolumeSource { // by clients and scheduled onto hosts. // +k8s:supportsSubresource="/status" // +k8s:supportsSubresource="/ephemeralcontainers" +// +k8s:supportsSubresource="/resize" +// +k8s:supportsSubresource="/eviction" message Pod { // Standard object's metadata. // More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata @@ -4604,6 +4606,7 @@ message PodSpec { // If specified, the pod's tolerations. // +optional // +listType=atomic + // +k8s:alpha(since: "1.37")=+k8s:optional repeated Toleration tolerations = 22; // HostAliases is an optional list of hosts and IPs that will be injected into the pod's hosts @@ -5452,6 +5455,7 @@ message ReplicationControllerSpec { // The only allowed template.spec.restartPolicy value is "Always". // More info: https://kubernetes.io/docs/concepts/workloads/controllers/replicationcontroller#pod-template // +optional + // +k8s:alpha(since: "1.37")=+k8s:optional optional PodTemplateSpec template = 3; } @@ -6638,6 +6642,8 @@ message Toleration { // Key is the taint key that the toleration applies to. Empty means match all taint keys. // If the key is empty, operator must be Exists; this combination means to match all values and all keys. // +optional + // +k8s:alpha(since: "1.37")=+k8s:optional + // +k8s:alpha(since: "1.37")=+k8s:format=k8s-label-key optional string key = 1; // Operator represents a key's relationship to the value. diff --git a/staging/src/k8s.io/api/extensions/v1beta1/zz_generated.validations.go b/staging/src/k8s.io/api/extensions/v1beta1/zz_generated.validations.go deleted file mode 100644 index 5d8f8ec3549..00000000000 --- a/staging/src/k8s.io/api/extensions/v1beta1/zz_generated.validations.go +++ /dev/null @@ -1,418 +0,0 @@ -//go:build !ignore_autogenerated -// +build !ignore_autogenerated - -/* -Copyright 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. -*/ - -// Code generated by validation-gen. DO NOT EDIT. - -package v1beta1 - -import ( - context "context" - fmt "fmt" - - equality "k8s.io/apimachinery/pkg/api/equality" - operation "k8s.io/apimachinery/pkg/api/operation" - safe "k8s.io/apimachinery/pkg/api/safe" - validate "k8s.io/apimachinery/pkg/api/validate" - runtime "k8s.io/apimachinery/pkg/runtime" - field "k8s.io/apimachinery/pkg/util/validation/field" -) - -func init() { localSchemeBuilder.Register(RegisterValidations) } - -// RegisterValidations adds validation functions to the given scheme. -// Public to allow building arbitrary schemes. -func RegisterValidations(scheme *runtime.Scheme) error { - // type NetworkPolicy - scheme.AddValidationFunc( - (*NetworkPolicy)(nil), - func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { - switch op.Request.SubresourcePath() { - case "/": - return Validate_NetworkPolicy( - ctx, op, nil, /* fldPath */ - obj.(*NetworkPolicy), - safe.Cast[*NetworkPolicy](oldObj)) - } - return field.ErrorList{ - field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), - } - }) - // type Scale - scheme.AddValidationFunc( - (*Scale)(nil), - func(ctx context.Context, op operation.Operation, obj, oldObj interface{}) field.ErrorList { - switch op.Request.SubresourcePath() { - case "/scale": - return Validate_Scale( - ctx, op, nil, /* fldPath */ - obj.(*Scale), - safe.Cast[*Scale](oldObj)) - } - return field.ErrorList{ - field.InternalError(nil, fmt.Errorf("no validation found for %T, subresource: %v", obj, op.Request.SubresourcePath())), - } - }) - return nil -} - -// Validate_IPBlock validates an instance of IPBlock according -// to declarative validation rules in the API schema. -func Validate_IPBlock( - ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *IPBlock) (errs field.ErrorList) { - - { // field IPBlock.CIDR - fn := func( - fldPath *field.Path, - obj, oldObj *string, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.RequiredValue(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { - errs = append(errs, e...) - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - return - } - oldVal := safe.Field(oldObj, - func(oldObj *IPBlock) *string { - return &oldObj.CIDR - }) - errs = append(errs, fn(fldPath.Child("cidr"), &obj.CIDR, oldVal, oldObj != nil)...) - } - - // field IPBlock.Except has no validation - return errs -} - -// Validate_NetworkPolicy validates an instance of NetworkPolicy according -// to declarative validation rules in the API schema. -func Validate_NetworkPolicy( - ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *NetworkPolicy) (errs field.ErrorList) { - - // field NetworkPolicy.TypeMeta has no validation - // field NetworkPolicy.ObjectMeta has no validation - - { // field NetworkPolicy.Spec - fn := func( - fldPath *field.Path, - obj, oldObj *NetworkPolicySpec, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if equality.Semantic.DeepEqual(obj, oldObj) { - return nil - } - } - // call the type's validation function - errs = append(errs, Validate_NetworkPolicySpec(ctx, op, fldPath, obj, oldObj)...) - return - } - oldVal := safe.Field(oldObj, - func(oldObj *NetworkPolicy) *NetworkPolicySpec { - return &oldObj.Spec - }) - errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) - } - - return errs -} - -// Validate_NetworkPolicyEgressRule validates an instance of NetworkPolicyEgressRule according -// to declarative validation rules in the API schema. -func Validate_NetworkPolicyEgressRule( - ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *NetworkPolicyEgressRule) (errs field.ErrorList) { - - // field NetworkPolicyEgressRule.Ports has no validation - - { // field NetworkPolicyEgressRule.To - fn := func( - fldPath *field.Path, - obj, oldObj []NetworkPolicyPeer, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if equality.Semantic.DeepEqual(obj, oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - // iterate the list and call the type's validation function - if e := validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_NetworkPolicyPeer); len(e) != 0 { - errs = append(errs, e...) - } - return - } - oldVal := safe.Field(oldObj, - func(oldObj *NetworkPolicyEgressRule) []NetworkPolicyPeer { - return oldObj.To - }) - errs = append(errs, fn(fldPath.Child("to"), obj.To, oldVal, oldObj != nil)...) - } - - return errs -} - -// Validate_NetworkPolicyIngressRule validates an instance of NetworkPolicyIngressRule according -// to declarative validation rules in the API schema. -func Validate_NetworkPolicyIngressRule( - ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *NetworkPolicyIngressRule) (errs field.ErrorList) { - - // field NetworkPolicyIngressRule.Ports has no validation - - { // field NetworkPolicyIngressRule.From - fn := func( - fldPath *field.Path, - obj, oldObj []NetworkPolicyPeer, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if equality.Semantic.DeepEqual(obj, oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - // iterate the list and call the type's validation function - if e := validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_NetworkPolicyPeer); len(e) != 0 { - errs = append(errs, e...) - } - return - } - oldVal := safe.Field(oldObj, - func(oldObj *NetworkPolicyIngressRule) []NetworkPolicyPeer { - return oldObj.From - }) - errs = append(errs, fn(fldPath.Child("from"), obj.From, oldVal, oldObj != nil)...) - } - - return errs -} - -// Validate_NetworkPolicyPeer validates an instance of NetworkPolicyPeer according -// to declarative validation rules in the API schema. -func Validate_NetworkPolicyPeer( - ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *NetworkPolicyPeer) (errs field.ErrorList) { - - // field NetworkPolicyPeer.PodSelector has no validation - // field NetworkPolicyPeer.NamespaceSelector has no validation - - { // field NetworkPolicyPeer.IPBlock - fn := func( - fldPath *field.Path, - obj, oldObj *IPBlock, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if equality.Semantic.DeepEqual(obj, oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.OptionalPointer(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - // call the type's validation function - errs = append(errs, Validate_IPBlock(ctx, op, fldPath, obj, oldObj)...) - return - } - oldVal := safe.Field(oldObj, - func(oldObj *NetworkPolicyPeer) *IPBlock { - return oldObj.IPBlock - }) - errs = append(errs, fn(fldPath.Child("ipBlock"), obj.IPBlock, oldVal, oldObj != nil)...) - } - - return errs -} - -// Validate_NetworkPolicySpec validates an instance of NetworkPolicySpec according -// to declarative validation rules in the API schema. -func Validate_NetworkPolicySpec( - ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *NetworkPolicySpec) (errs field.ErrorList) { - - // field NetworkPolicySpec.PodSelector has no validation - - { // field NetworkPolicySpec.Ingress - fn := func( - fldPath *field.Path, - obj, oldObj []NetworkPolicyIngressRule, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if equality.Semantic.DeepEqual(obj, oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - // iterate the list and call the type's validation function - if e := validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_NetworkPolicyIngressRule); len(e) != 0 { - errs = append(errs, e...) - } - return - } - oldVal := safe.Field(oldObj, - func(oldObj *NetworkPolicySpec) []NetworkPolicyIngressRule { - return oldObj.Ingress - }) - errs = append(errs, fn(fldPath.Child("ingress"), obj.Ingress, oldVal, oldObj != nil)...) - } - - { // field NetworkPolicySpec.Egress - fn := func( - fldPath *field.Path, - obj, oldObj []NetworkPolicyEgressRule, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if equality.Semantic.DeepEqual(obj, oldObj) { - return nil - } - } - // call field-attached validations - earlyReturn := false - if e := validate.OptionalSlice(ctx, op, fldPath, obj, oldObj).MarkAlpha().MarkShortCircuit(); len(e) != 0 { - earlyReturn = true - } - if earlyReturn { - return // do not proceed - } - // iterate the list and call the type's validation function - if e := validate.EachSliceVal(ctx, op, fldPath, obj, oldObj, nil, nil, Validate_NetworkPolicyEgressRule); len(e) != 0 { - errs = append(errs, e...) - } - return - } - oldVal := safe.Field(oldObj, - func(oldObj *NetworkPolicySpec) []NetworkPolicyEgressRule { - return oldObj.Egress - }) - errs = append(errs, fn(fldPath.Child("egress"), obj.Egress, oldVal, oldObj != nil)...) - } - - // field NetworkPolicySpec.PolicyTypes has no validation - return errs -} - -// Validate_Scale validates an instance of Scale according -// to declarative validation rules in the API schema. -func Validate_Scale( - ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *Scale) (errs field.ErrorList) { - - // field Scale.TypeMeta has no validation - // field Scale.ObjectMeta has no validation - - { // field Scale.Spec - fn := func( - fldPath *field.Path, - obj, oldObj *ScaleSpec, - oldValueCorrelated bool) (errs field.ErrorList) { - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { - return nil - } - } - // call the type's validation function - errs = append(errs, Validate_ScaleSpec(ctx, op, fldPath, obj, oldObj)...) - return - } - oldVal := safe.Field(oldObj, - func(oldObj *Scale) *ScaleSpec { - return &oldObj.Spec - }) - errs = append(errs, fn(fldPath.Child("spec"), &obj.Spec, oldVal, oldObj != nil)...) - } - - // field Scale.Status has no validation - return errs -} - -// Validate_ScaleSpec validates an instance of ScaleSpec according -// to declarative validation rules in the API schema. -func Validate_ScaleSpec( - ctx context.Context, op operation.Operation, fldPath *field.Path, - obj, oldObj *ScaleSpec) (errs field.ErrorList) { - - { // field ScaleSpec.Replicas - fn := func( - fldPath *field.Path, - obj, oldObj *int32, - oldValueCorrelated bool) (errs field.ErrorList) { - // optional value-type fields with zero-value defaults are purely documentation - // don't revalidate unchanged data - if oldValueCorrelated && op.Type == operation.Update { - if obj == oldObj || (obj != nil && oldObj != nil && *obj == *oldObj) { - return nil - } - } - // call field-attached validations - if e := validate.Minimum(ctx, op, fldPath, obj, oldObj, 0).MarkAlpha(); len(e) != 0 { - errs = append(errs, e...) - } - return - } - oldVal := safe.Field(oldObj, - func(oldObj *ScaleSpec) *int32 { - return &oldObj.Replicas - }) - errs = append(errs, fn(fldPath.Child("replicas"), &obj.Replicas, oldVal, oldObj != nil)...) - } - - return errs -} diff --git a/staging/src/k8s.io/api/node/v1/generated.proto b/staging/src/k8s.io/api/node/v1/generated.proto index 4d77c9b7810..20873270930 100644 --- a/staging/src/k8s.io/api/node/v1/generated.proto +++ b/staging/src/k8s.io/api/node/v1/generated.proto @@ -76,6 +76,7 @@ message RuntimeClass { // If scheduling is nil, this RuntimeClass is assumed to be supported by all // nodes. // +optional + // +k8s:alpha(since: "1.37")=+k8s:optional optional Scheduling scheduling = 4; } @@ -107,6 +108,7 @@ message Scheduling { // tolerated by the pod and the RuntimeClass. // +optional // +listType=atomic + // +k8s:alpha(since: "1.37")=+k8s:optional repeated .k8s.io.api.core.v1.Toleration tolerations = 2; } diff --git a/staging/src/k8s.io/api/node/v1alpha1/generated.proto b/staging/src/k8s.io/api/node/v1alpha1/generated.proto index c50b639065e..e328716a68d 100644 --- a/staging/src/k8s.io/api/node/v1alpha1/generated.proto +++ b/staging/src/k8s.io/api/node/v1alpha1/generated.proto @@ -98,6 +98,7 @@ message RuntimeClassSpec { // If scheduling is nil, this RuntimeClass is assumed to be supported by all // nodes. // +optional + // +k8s:alpha(since: "1.37")=+k8s:optional optional Scheduling scheduling = 3; } @@ -118,6 +119,7 @@ message Scheduling { // tolerated by the pod and the RuntimeClass. // +optional // +listType=atomic + // +k8s:alpha(since: "1.37")=+k8s:optional repeated .k8s.io.api.core.v1.Toleration tolerations = 2; } diff --git a/staging/src/k8s.io/api/node/v1beta1/generated.proto b/staging/src/k8s.io/api/node/v1beta1/generated.proto index 073a185e2c4..0fd9241bd74 100644 --- a/staging/src/k8s.io/api/node/v1beta1/generated.proto +++ b/staging/src/k8s.io/api/node/v1beta1/generated.proto @@ -76,6 +76,7 @@ message RuntimeClass { // If scheduling is nil, this RuntimeClass is assumed to be supported by all // nodes. // +optional + // +k8s:alpha(since: "1.37")=+k8s:optional optional Scheduling scheduling = 4; } @@ -107,6 +108,7 @@ message Scheduling { // tolerated by the pod and the RuntimeClass. // +optional // +listType=atomic + // +k8s:alpha(since: "1.37")=+k8s:optional repeated .k8s.io.api.core.v1.Toleration tolerations = 2; } diff --git a/test/declarative_validation/apps/daemonset/zz_generated.validations.main_test.go b/test/declarative_validation/apps/daemonset/zz_generated.validations.main_test.go new file mode 100644 index 00000000000..c9c159fcc48 --- /dev/null +++ b/test/declarative_validation/apps/daemonset/zz_generated.validations.main_test.go @@ -0,0 +1,43 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package daemonset + +import ( + fmt "fmt" + os "os" + testing "testing" + + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +var apiVersions = []string{"v1", "v1beta2"} + +func TestMain(m *testing.M) { + code := m.Run() + if err := coverage.AssertDeclarativeCoverage(); err != nil { + fmt.Fprintln(os.Stderr, err) + if code == 0 { + code = 1 + } + } + os.Exit(code) +} diff --git a/test/declarative_validation/apps/daemonset/zz_generated.validations.v1_test.go b/test/declarative_validation/apps/daemonset/zz_generated.validations.v1_test.go new file mode 100644 index 00000000000..8f169b8ed81 --- /dev/null +++ b/test/declarative_validation/apps/daemonset/zz_generated.validations.v1_test.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package daemonset + +import ( + schema "k8s.io/apimachinery/pkg/runtime/schema" + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +func init() { + coverage.RegisterDeclaredRules( + schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "DaemonSet"}, + coverage.FieldRules{ + "spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, + }, + ) +} diff --git a/test/declarative_validation/apps/daemonset/zz_generated.validations.v1beta2_test.go b/test/declarative_validation/apps/daemonset/zz_generated.validations.v1beta2_test.go new file mode 100644 index 00000000000..a424bce5bda --- /dev/null +++ b/test/declarative_validation/apps/daemonset/zz_generated.validations.v1beta2_test.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package daemonset + +import ( + schema "k8s.io/apimachinery/pkg/runtime/schema" + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +func init() { + coverage.RegisterDeclaredRules( + schema.GroupVersionKind{Group: "apps", Version: "v1beta2", Kind: "DaemonSet"}, + coverage.FieldRules{ + "spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, + }, + ) +} diff --git a/test/declarative_validation/apps/deployment/zz_generated.validations.main_test.go b/test/declarative_validation/apps/deployment/zz_generated.validations.main_test.go new file mode 100644 index 00000000000..435b0328e8b --- /dev/null +++ b/test/declarative_validation/apps/deployment/zz_generated.validations.main_test.go @@ -0,0 +1,43 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package deployment + +import ( + fmt "fmt" + os "os" + testing "testing" + + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +var apiVersions = []string{"v1", "v1beta1", "v1beta2"} + +func TestMain(m *testing.M) { + code := m.Run() + if err := coverage.AssertDeclarativeCoverage(); err != nil { + fmt.Fprintln(os.Stderr, err) + if code == 0 { + code = 1 + } + } + os.Exit(code) +} diff --git a/test/declarative_validation/apps/deployment/zz_generated.validations.v1_test.go b/test/declarative_validation/apps/deployment/zz_generated.validations.v1_test.go new file mode 100644 index 00000000000..4b69e63adc4 --- /dev/null +++ b/test/declarative_validation/apps/deployment/zz_generated.validations.v1_test.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package deployment + +import ( + schema "k8s.io/apimachinery/pkg/runtime/schema" + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +func init() { + coverage.RegisterDeclaredRules( + schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "Deployment"}, + coverage.FieldRules{ + "spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, + }, + ) +} diff --git a/test/declarative_validation/apps/deployment/zz_generated.validations.v1beta1_test.go b/test/declarative_validation/apps/deployment/zz_generated.validations.v1beta1_test.go new file mode 100644 index 00000000000..a00098c34cc --- /dev/null +++ b/test/declarative_validation/apps/deployment/zz_generated.validations.v1beta1_test.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package deployment + +import ( + schema "k8s.io/apimachinery/pkg/runtime/schema" + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +func init() { + coverage.RegisterDeclaredRules( + schema.GroupVersionKind{Group: "apps", Version: "v1beta1", Kind: "Deployment"}, + coverage.FieldRules{ + "spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, + }, + ) +} diff --git a/test/declarative_validation/apps/deployment/zz_generated.validations.v1beta2_test.go b/test/declarative_validation/apps/deployment/zz_generated.validations.v1beta2_test.go new file mode 100644 index 00000000000..bc2aeaed98f --- /dev/null +++ b/test/declarative_validation/apps/deployment/zz_generated.validations.v1beta2_test.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package deployment + +import ( + schema "k8s.io/apimachinery/pkg/runtime/schema" + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +func init() { + coverage.RegisterDeclaredRules( + schema.GroupVersionKind{Group: "apps", Version: "v1beta2", Kind: "Deployment"}, + coverage.FieldRules{ + "spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, + }, + ) +} diff --git a/test/declarative_validation/apps/replicaset/zz_generated.validations.main_test.go b/test/declarative_validation/apps/replicaset/zz_generated.validations.main_test.go new file mode 100644 index 00000000000..b08140d82b0 --- /dev/null +++ b/test/declarative_validation/apps/replicaset/zz_generated.validations.main_test.go @@ -0,0 +1,43 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package replicaset + +import ( + fmt "fmt" + os "os" + testing "testing" + + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +var apiVersions = []string{"v1", "v1beta2"} + +func TestMain(m *testing.M) { + code := m.Run() + if err := coverage.AssertDeclarativeCoverage(); err != nil { + fmt.Fprintln(os.Stderr, err) + if code == 0 { + code = 1 + } + } + os.Exit(code) +} diff --git a/test/declarative_validation/apps/replicaset/zz_generated.validations.v1_test.go b/test/declarative_validation/apps/replicaset/zz_generated.validations.v1_test.go new file mode 100644 index 00000000000..dcd6b63b4d7 --- /dev/null +++ b/test/declarative_validation/apps/replicaset/zz_generated.validations.v1_test.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package replicaset + +import ( + schema "k8s.io/apimachinery/pkg/runtime/schema" + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +func init() { + coverage.RegisterDeclaredRules( + schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "ReplicaSet"}, + coverage.FieldRules{ + "spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, + }, + ) +} diff --git a/test/declarative_validation/apps/replicaset/zz_generated.validations.v1beta2_test.go b/test/declarative_validation/apps/replicaset/zz_generated.validations.v1beta2_test.go new file mode 100644 index 00000000000..4c7a0296cc9 --- /dev/null +++ b/test/declarative_validation/apps/replicaset/zz_generated.validations.v1beta2_test.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package replicaset + +import ( + schema "k8s.io/apimachinery/pkg/runtime/schema" + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +func init() { + coverage.RegisterDeclaredRules( + schema.GroupVersionKind{Group: "apps", Version: "v1beta2", Kind: "ReplicaSet"}, + coverage.FieldRules{ + "spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, + }, + ) +} diff --git a/test/declarative_validation/apps/statefulset/zz_generated.validations.main_test.go b/test/declarative_validation/apps/statefulset/zz_generated.validations.main_test.go new file mode 100644 index 00000000000..260c7e8e739 --- /dev/null +++ b/test/declarative_validation/apps/statefulset/zz_generated.validations.main_test.go @@ -0,0 +1,43 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package statefulset + +import ( + fmt "fmt" + os "os" + testing "testing" + + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +var apiVersions = []string{"v1", "v1beta1", "v1beta2"} + +func TestMain(m *testing.M) { + code := m.Run() + if err := coverage.AssertDeclarativeCoverage(); err != nil { + fmt.Fprintln(os.Stderr, err) + if code == 0 { + code = 1 + } + } + os.Exit(code) +} diff --git a/test/declarative_validation/apps/statefulset/zz_generated.validations.v1_test.go b/test/declarative_validation/apps/statefulset/zz_generated.validations.v1_test.go new file mode 100644 index 00000000000..d7a22446e19 --- /dev/null +++ b/test/declarative_validation/apps/statefulset/zz_generated.validations.v1_test.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package statefulset + +import ( + schema "k8s.io/apimachinery/pkg/runtime/schema" + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +func init() { + coverage.RegisterDeclaredRules( + schema.GroupVersionKind{Group: "apps", Version: "v1", Kind: "StatefulSet"}, + coverage.FieldRules{ + "spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, + }, + ) +} diff --git a/test/declarative_validation/apps/statefulset/zz_generated.validations.v1beta1_test.go b/test/declarative_validation/apps/statefulset/zz_generated.validations.v1beta1_test.go new file mode 100644 index 00000000000..a611fa55508 --- /dev/null +++ b/test/declarative_validation/apps/statefulset/zz_generated.validations.v1beta1_test.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package statefulset + +import ( + schema "k8s.io/apimachinery/pkg/runtime/schema" + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +func init() { + coverage.RegisterDeclaredRules( + schema.GroupVersionKind{Group: "apps", Version: "v1beta1", Kind: "StatefulSet"}, + coverage.FieldRules{ + "spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, + }, + ) +} diff --git a/test/declarative_validation/apps/statefulset/zz_generated.validations.v1beta2_test.go b/test/declarative_validation/apps/statefulset/zz_generated.validations.v1beta2_test.go new file mode 100644 index 00000000000..6c182abcf6b --- /dev/null +++ b/test/declarative_validation/apps/statefulset/zz_generated.validations.v1beta2_test.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package statefulset + +import ( + schema "k8s.io/apimachinery/pkg/runtime/schema" + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +func init() { + coverage.RegisterDeclaredRules( + schema.GroupVersionKind{Group: "apps", Version: "v1beta2", Kind: "StatefulSet"}, + coverage.FieldRules{ + "spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, + }, + ) +} diff --git a/test/declarative_validation/batch/cronjob/zz_generated.validations.v1_test.go b/test/declarative_validation/batch/cronjob/zz_generated.validations.v1_test.go index 9c307bf5b9c..6e3c112b215 100644 --- a/test/declarative_validation/batch/cronjob/zz_generated.validations.v1_test.go +++ b/test/declarative_validation/batch/cronjob/zz_generated.validations.v1_test.go @@ -33,6 +33,9 @@ func init() { "spec.jobTemplate.spec.backoffLimitPerIndex": { {ErrorType: "FieldValueRequired", Origin: "dependentRequired"}, }, + "spec.jobTemplate.spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, "spec.schedule": { {ErrorType: "FieldValueRequired"}, }, diff --git a/test/declarative_validation/batch/cronjob/zz_generated.validations.v1beta1_test.go b/test/declarative_validation/batch/cronjob/zz_generated.validations.v1beta1_test.go index 3a3c912c543..1d34dc007bd 100644 --- a/test/declarative_validation/batch/cronjob/zz_generated.validations.v1beta1_test.go +++ b/test/declarative_validation/batch/cronjob/zz_generated.validations.v1beta1_test.go @@ -33,6 +33,9 @@ func init() { "spec.jobTemplate.spec.backoffLimitPerIndex": { {ErrorType: "FieldValueRequired", Origin: "dependentRequired"}, }, + "spec.jobTemplate.spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, "spec.schedule": { {ErrorType: "FieldValueRequired"}, }, diff --git a/test/declarative_validation/batch/job/zz_generated.validations.v1_test.go b/test/declarative_validation/batch/job/zz_generated.validations.v1_test.go index 912f0d85f25..18d9563d8d1 100644 --- a/test/declarative_validation/batch/job/zz_generated.validations.v1_test.go +++ b/test/declarative_validation/batch/job/zz_generated.validations.v1_test.go @@ -33,6 +33,9 @@ func init() { "spec.backoffLimitPerIndex": { {ErrorType: "FieldValueRequired", Origin: "dependentRequired"}, }, + "spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, }, ) } diff --git a/test/declarative_validation/core/pod/zz_generated.validations.main_test.go b/test/declarative_validation/core/pod/zz_generated.validations.main_test.go new file mode 100644 index 00000000000..31c1adffc4f --- /dev/null +++ b/test/declarative_validation/core/pod/zz_generated.validations.main_test.go @@ -0,0 +1,43 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package pod + +import ( + fmt "fmt" + os "os" + testing "testing" + + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +var apiVersions = []string{"v1"} + +func TestMain(m *testing.M) { + code := m.Run() + if err := coverage.AssertDeclarativeCoverage(); err != nil { + fmt.Fprintln(os.Stderr, err) + if code == 0 { + code = 1 + } + } + os.Exit(code) +} diff --git a/test/declarative_validation/core/pod/zz_generated.validations.v1_test.go b/test/declarative_validation/core/pod/zz_generated.validations.v1_test.go new file mode 100644 index 00000000000..1b0f8c82995 --- /dev/null +++ b/test/declarative_validation/core/pod/zz_generated.validations.v1_test.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package pod + +import ( + schema "k8s.io/apimachinery/pkg/runtime/schema" + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +func init() { + coverage.RegisterDeclaredRules( + schema.GroupVersionKind{Group: "", Version: "v1", Kind: "Pod"}, + coverage.FieldRules{ + "spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, + }, + ) +} diff --git a/test/declarative_validation/core/podtemplate/zz_generated.validations.main_test.go b/test/declarative_validation/core/podtemplate/zz_generated.validations.main_test.go new file mode 100644 index 00000000000..6b26035621f --- /dev/null +++ b/test/declarative_validation/core/podtemplate/zz_generated.validations.main_test.go @@ -0,0 +1,43 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package podtemplate + +import ( + fmt "fmt" + os "os" + testing "testing" + + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +var apiVersions = []string{"v1"} + +func TestMain(m *testing.M) { + code := m.Run() + if err := coverage.AssertDeclarativeCoverage(); err != nil { + fmt.Fprintln(os.Stderr, err) + if code == 0 { + code = 1 + } + } + os.Exit(code) +} diff --git a/test/declarative_validation/core/podtemplate/zz_generated.validations.v1_test.go b/test/declarative_validation/core/podtemplate/zz_generated.validations.v1_test.go new file mode 100644 index 00000000000..1415f94c175 --- /dev/null +++ b/test/declarative_validation/core/podtemplate/zz_generated.validations.v1_test.go @@ -0,0 +1,38 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +/* +Copyright 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. +*/ + +// Code generated by validation-gen. DO NOT EDIT. + +package podtemplate + +import ( + schema "k8s.io/apimachinery/pkg/runtime/schema" + coverage "k8s.io/apimachinery/pkg/test/coverage" +) + +func init() { + coverage.RegisterDeclaredRules( + schema.GroupVersionKind{Group: "", Version: "v1", Kind: "PodTemplate"}, + coverage.FieldRules{ + "template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, + }, + ) +} diff --git a/test/declarative_validation/core/replicationcontroller/zz_generated.validations.v1_test.go b/test/declarative_validation/core/replicationcontroller/zz_generated.validations.v1_test.go index 2b582618f0f..68d7457fd59 100644 --- a/test/declarative_validation/core/replicationcontroller/zz_generated.validations.v1_test.go +++ b/test/declarative_validation/core/replicationcontroller/zz_generated.validations.v1_test.go @@ -40,6 +40,9 @@ func init() { {ErrorType: "FieldValueInvalid", Origin: "minimum"}, {ErrorType: "FieldValueRequired"}, }, + "spec.template.spec.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, }, ) } diff --git a/test/declarative_validation/node/runtimeclass/zz_generated.validations.v1_test.go b/test/declarative_validation/node/runtimeclass/zz_generated.validations.v1_test.go index 54d34e32744..0266c93862b 100644 --- a/test/declarative_validation/node/runtimeclass/zz_generated.validations.v1_test.go +++ b/test/declarative_validation/node/runtimeclass/zz_generated.validations.v1_test.go @@ -35,6 +35,9 @@ func init() { {ErrorType: "FieldValueInvalid", Origin: "immutable"}, {ErrorType: "FieldValueRequired"}, }, + "scheduling.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, }, ) } diff --git a/test/declarative_validation/node/runtimeclass/zz_generated.validations.v1alpha1_test.go b/test/declarative_validation/node/runtimeclass/zz_generated.validations.v1alpha1_test.go index 2bf676d49d7..31b3eb99cd2 100644 --- a/test/declarative_validation/node/runtimeclass/zz_generated.validations.v1alpha1_test.go +++ b/test/declarative_validation/node/runtimeclass/zz_generated.validations.v1alpha1_test.go @@ -35,6 +35,9 @@ func init() { {ErrorType: "FieldValueInvalid", Origin: "immutable"}, {ErrorType: "FieldValueRequired"}, }, + "spec.scheduling.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, }, ) } diff --git a/test/declarative_validation/node/runtimeclass/zz_generated.validations.v1beta1_test.go b/test/declarative_validation/node/runtimeclass/zz_generated.validations.v1beta1_test.go index 546371682f5..0271007786b 100644 --- a/test/declarative_validation/node/runtimeclass/zz_generated.validations.v1beta1_test.go +++ b/test/declarative_validation/node/runtimeclass/zz_generated.validations.v1beta1_test.go @@ -35,6 +35,9 @@ func init() { {ErrorType: "FieldValueInvalid", Origin: "immutable"}, {ErrorType: "FieldValueRequired"}, }, + "scheduling.tolerations[*].key": { + {ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"}, + }, }, ) } From e4cc8f8e9d5263b520820c2a105b780ae4acc04b Mon Sep 17 00:00:00 2001 From: Yongrui Lin Date: Tue, 9 Jun 2026 20:56:55 +0000 Subject: [PATCH 06/10] testing: skip unserved extensions/v1beta1 in validation equivalence sweep Add WithSkipGroupVersions and apply it to the NetworkPolicy and Scale tests, whose internal types also register under the now-unvalidated extensions/v1beta1. --- pkg/api/testing/validation.go | 24 +++++++++++++++++++ .../apps/scale/declarative_validation_test.go | 2 +- .../scale/declarative_validation_test.go | 2 +- .../declarative_validation_test.go | 6 +++++ 4 files changed, 32 insertions(+), 2 deletions(-) diff --git a/pkg/api/testing/validation.go b/pkg/api/testing/validation.go index 39525d3dda0..3229b235539 100644 --- a/pkg/api/testing/validation.go +++ b/pkg/api/testing/validation.go @@ -29,6 +29,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" runtimetest "k8s.io/apimachinery/pkg/runtime/testing" "k8s.io/apimachinery/pkg/test/coverage" + "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/validation/field" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/features" @@ -55,6 +56,12 @@ func VerifyVersionedValidationEquivalence(t *testing.T, obj, old runtime.Object, // Accumulate errors from all versioned validation, per version. all := map[string]field.ErrorList{} accumulate := func(t *testing.T, gv string, errs field.ErrorList) { + // Skip versions explicitly excluded from the equivalence sweep (e.g. a + // deprecated, unserved group whose types are intentionally not validated + // declaratively). + if opts.SkipGroupVersions.Has(gv) { + return + } // If normalization rules are provided, apply them to the field paths of generated errors. // This allows comparing errors between API versions that have structural differences // (e.g. flattened vs nested fields). @@ -222,6 +229,13 @@ type validationOption struct { // Fuzzer is the fuzzer to use for generating test objects. Fuzzer *randfill.Filler + + // SkipGroupVersions lists "group/version" strings to exclude from the + // versioned validation equivalence sweep. This is for kinds whose internal + // type is registered under a deprecated, unserved group (e.g. a workload + // type that also exists in extensions/v1beta1) for which declarative + // validation is intentionally not generated. + SkipGroupVersions sets.Set[string] } func WithSubResources(subResources ...string) ValidationTestConfig { @@ -248,6 +262,16 @@ func WithFuzzer(fuzzer *randfill.Filler) ValidationTestConfig { } } +// WithSkipGroupVersions excludes the given "group/version" strings from the +// versioned validation equivalence sweep. Use it for kinds whose internal type +// is also registered under a deprecated, unserved group (e.g. extensions/v1beta1) +// for which declarative validation is intentionally not generated. +func WithSkipGroupVersions(groupVersions ...string) ValidationTestConfig { + return func(o *validationOption) { + o.SkipGroupVersions = sets.New(groupVersions...) + } +} + // VerifyValidationEquivalence provides a helper for testing the migration from // hand-written imperative validation to declarative validation. It ensures that // the validation logic remains consistent across enforcement modes. diff --git a/test/declarative_validation/apps/scale/declarative_validation_test.go b/test/declarative_validation/apps/scale/declarative_validation_test.go index 841e4ae59dd..e905e226bff 100644 --- a/test/declarative_validation/apps/scale/declarative_validation_test.go +++ b/test/declarative_validation/apps/scale/declarative_validation_test.go @@ -61,7 +61,7 @@ func TestDeclarativeValidateUpdate(t *testing.T) { t.Run(k, func(t *testing.T) { tc.old.ResourceVersion = "1" tc.update.ResourceVersion = "1" - apitesting.VerifyUpdateValidationEquivalenceFunc(t, ctx, &tc.update, &tc.old, validateScale, tc.expectedErrs, apitesting.WithSubResources("scale")) + apitesting.VerifyUpdateValidationEquivalenceFunc(t, ctx, &tc.update, &tc.old, validateScale, tc.expectedErrs, apitesting.WithSubResources("scale"), apitesting.WithSkipGroupVersions("extensions/v1beta1")) }) } }) diff --git a/test/declarative_validation/autoscaling/scale/declarative_validation_test.go b/test/declarative_validation/autoscaling/scale/declarative_validation_test.go index 58d6fd8b0fc..9c51bfb2f97 100644 --- a/test/declarative_validation/autoscaling/scale/declarative_validation_test.go +++ b/test/declarative_validation/autoscaling/scale/declarative_validation_test.go @@ -61,7 +61,7 @@ func TestDeclarativeValidateUpdate(t *testing.T) { t.Run(k, func(t *testing.T) { tc.old.ResourceVersion = "1" tc.update.ResourceVersion = "1" - apitesting.VerifyUpdateValidationEquivalenceFunc(t, ctx, &tc.update, &tc.old, validateScale, tc.expectedErrs, apitesting.WithSubResources("scale")) + apitesting.VerifyUpdateValidationEquivalenceFunc(t, ctx, &tc.update, &tc.old, validateScale, tc.expectedErrs, apitesting.WithSubResources("scale"), apitesting.WithSkipGroupVersions("extensions/v1beta1")) }) } }) diff --git a/test/declarative_validation/networking/networkpolicy/declarative_validation_test.go b/test/declarative_validation/networking/networkpolicy/declarative_validation_test.go index 91aeb9e8b20..be5b0890ab0 100644 --- a/test/declarative_validation/networking/networkpolicy/declarative_validation_test.go +++ b/test/declarative_validation/networking/networkpolicy/declarative_validation_test.go @@ -80,6 +80,9 @@ func TestDeclarativeValidateIPBlockCIDR(t *testing.T) { &tc.input, registry.Strategy, tc.expectedErrs, + // extensions/v1beta1 is unserved and no longer carries + // declarative validation; skip it in the version sweep. + apitesting.WithSkipGroupVersions("extensions/v1beta1"), ) }) } @@ -148,6 +151,9 @@ func TestDeclarativeValidateIPBlockCIDRUpdate(t *testing.T) { &tc.oldObj, registry.Strategy, tc.expectedErrs, + // extensions/v1beta1 is unserved and no longer carries + // declarative validation; skip it in the version sweep. + apitesting.WithSkipGroupVersions("extensions/v1beta1"), ) }) } From ca4ae01f4d1176eba601ed33e790c262979f4c75 Mon Sep 17 00:00:00 2001 From: Yongrui Lin Date: Tue, 9 Jun 2026 20:56:55 +0000 Subject: [PATCH 07/10] core: add declarative validation tests for toleration key Pod, PodTemplate, and ReplicationController; prefixed and unprefixed keys. --- .../core/pod/declarative_validation_test.go | 73 +++++++++++++++++++ .../declarative_validation_test.go | 73 +++++++++++++++++++ .../declarative_validation_test.go | 19 +++++ 3 files changed, 165 insertions(+) create mode 100644 test/declarative_validation/core/pod/declarative_validation_test.go create mode 100644 test/declarative_validation/core/podtemplate/declarative_validation_test.go diff --git a/test/declarative_validation/core/pod/declarative_validation_test.go b/test/declarative_validation/core/pod/declarative_validation_test.go new file mode 100644 index 00000000000..0eed614a499 --- /dev/null +++ b/test/declarative_validation/core/pod/declarative_validation_test.go @@ -0,0 +1,73 @@ +/* +Copyright 2025 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 pod + +import ( + "testing" + + "k8s.io/apimachinery/pkg/util/validation/field" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" + apitesting "k8s.io/kubernetes/pkg/api/testing" + api "k8s.io/kubernetes/pkg/apis/core" + registry "k8s.io/kubernetes/pkg/registry/core/pod" +) + +func TestDeclarativeValidate(t *testing.T) { + for _, apiVersion := range apiVersions { + ctx := genericapirequest.WithRequestInfo(genericapirequest.NewDefaultContext(), &genericapirequest.RequestInfo{ + APIGroup: "", + APIVersion: apiVersion, + }) + testCases := map[string]struct { + input *api.Pod + expectedErrs field.ErrorList + }{ + "valid": { + input: podtest.MakePod("foo"), + }, + "valid toleration key": { + input: podtest.MakePod("foo", podtest.SetTolerations( + api.Toleration{Key: "example.com/valid-key", Operator: api.TolerationOpExists}, + )), + }, + "valid toleration key without prefix": { + input: podtest.MakePod("foo", podtest.SetTolerations( + api.Toleration{Key: "simple-key", Operator: api.TolerationOpExists}, + )), + }, + "empty toleration key (match all, skipped)": { + input: podtest.MakePod("foo", podtest.SetTolerations( + api.Toleration{Operator: api.TolerationOpExists}, + )), + }, + "invalid toleration key format": { + input: podtest.MakePod("foo", podtest.SetTolerations( + api.Toleration{Key: "invalid key", Operator: api.TolerationOpExists}, + )), + expectedErrs: field.ErrorList{ + field.Invalid(field.NewPath("spec", "tolerations").Index(0).Child("key"), nil, "").WithOrigin("format=k8s-label-key").MarkAlpha(), + }, + }, + } + for k, tc := range testCases { + t.Run(k, func(t *testing.T) { + apitesting.VerifyValidationEquivalence(t, ctx, tc.input, registry.Strategy, tc.expectedErrs) + }) + } + } +} diff --git a/test/declarative_validation/core/podtemplate/declarative_validation_test.go b/test/declarative_validation/core/podtemplate/declarative_validation_test.go new file mode 100644 index 00000000000..1e974fbc9ee --- /dev/null +++ b/test/declarative_validation/core/podtemplate/declarative_validation_test.go @@ -0,0 +1,73 @@ +/* +Copyright 2025 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 podtemplate + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" + apitesting "k8s.io/kubernetes/pkg/api/testing" + api "k8s.io/kubernetes/pkg/apis/core" + registry "k8s.io/kubernetes/pkg/registry/core/podtemplate" +) + +func mkPodTemplate(tolerations ...api.Toleration) *api.PodTemplate { + return &api.PodTemplate{ + ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: metav1.NamespaceDefault}, + Template: api.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"a": "b"}}, + Spec: podtest.MakePodSpec(podtest.SetTolerations(tolerations...)), + }, + } +} + +func TestDeclarativeValidate(t *testing.T) { + for _, apiVersion := range apiVersions { + ctx := genericapirequest.WithRequestInfo(genericapirequest.NewDefaultContext(), &genericapirequest.RequestInfo{ + APIGroup: "", + APIVersion: apiVersion, + }) + testCases := map[string]struct { + input *api.PodTemplate + expectedErrs field.ErrorList + }{ + "valid": { + input: mkPodTemplate(), + }, + "valid toleration key": { + input: mkPodTemplate(api.Toleration{Key: "example.com/valid-key", Operator: api.TolerationOpExists}), + }, + "valid toleration key without prefix": { + input: mkPodTemplate(api.Toleration{Key: "simple-key", Operator: api.TolerationOpExists}), + }, + "invalid toleration key format": { + input: mkPodTemplate(api.Toleration{Key: "invalid key", Operator: api.TolerationOpExists}), + expectedErrs: field.ErrorList{ + field.Invalid(field.NewPath("template", "spec", "tolerations").Index(0).Child("key"), nil, "").WithOrigin("format=k8s-label-key").MarkAlpha(), + }, + }, + } + for k, tc := range testCases { + t.Run(k, func(t *testing.T) { + apitesting.VerifyValidationEquivalence(t, ctx, tc.input, registry.Strategy, tc.expectedErrs) + }) + } + } +} diff --git a/test/declarative_validation/core/replicationcontroller/declarative_validation_test.go b/test/declarative_validation/core/replicationcontroller/declarative_validation_test.go index 21787bfb70b..d43d888abed 100644 --- a/test/declarative_validation/core/replicationcontroller/declarative_validation_test.go +++ b/test/declarative_validation/core/replicationcontroller/declarative_validation_test.go @@ -187,6 +187,19 @@ func TestDeclarativeValidate(t *testing.T) { field.Invalid(field.NewPath("spec.minReadySeconds"), nil, "").WithOrigin("minimum").MarkAlpha(), }, }, + // spec.template.spec.tolerations[*].key + "tolerations: valid key": { + input: mkValidReplicationController(setSpecTolerations(api.Toleration{Key: "example.com/valid-key", Operator: api.TolerationOpExists})), + }, + "tolerations: valid key without prefix": { + input: mkValidReplicationController(setSpecTolerations(api.Toleration{Key: "simple-key", Operator: api.TolerationOpExists})), + }, + "tolerations: invalid key format": { + input: mkValidReplicationController(setSpecTolerations(api.Toleration{Key: "invalid key", Operator: api.TolerationOpExists})), + expectedErrs: field.ErrorList{ + field.Invalid(field.NewPath("spec.template.spec.tolerations").Index(0).Child("key"), nil, "").WithOrigin("format=k8s-label-key").MarkAlpha(), + }, + }, } for k, tc := range testCases { t.Run(k, func(t *testing.T) { @@ -313,3 +326,9 @@ func setSpecMinReadySeconds(val int32) func(rc *api.ReplicationController) { rc.Spec.MinReadySeconds = val } } + +func setSpecTolerations(tolerations ...api.Toleration) func(rc *api.ReplicationController) { + return func(rc *api.ReplicationController) { + rc.Spec.Template.Spec.Tolerations = tolerations + } +} From 627834ba06a70ede314131c7b29701455c9fe434 Mon Sep 17 00:00:00 2001 From: Yongrui Lin Date: Tue, 9 Jun 2026 20:56:55 +0000 Subject: [PATCH 08/10] apps: add declarative validation tests for toleration key Deployment, DaemonSet, ReplicaSet, and StatefulSet; prefixed and unprefixed keys. --- .../daemonset/declarative_validation_test.go | 79 +++++++++++++++++ .../deployment/declarative_validation_test.go | 86 +++++++++++++++++++ .../replicaset/declarative_validation_test.go | 78 +++++++++++++++++ .../declarative_validation_test.go | 79 +++++++++++++++++ 4 files changed, 322 insertions(+) create mode 100644 test/declarative_validation/apps/daemonset/declarative_validation_test.go create mode 100644 test/declarative_validation/apps/deployment/declarative_validation_test.go create mode 100644 test/declarative_validation/apps/replicaset/declarative_validation_test.go create mode 100644 test/declarative_validation/apps/statefulset/declarative_validation_test.go diff --git a/test/declarative_validation/apps/daemonset/declarative_validation_test.go b/test/declarative_validation/apps/daemonset/declarative_validation_test.go new file mode 100644 index 00000000000..169c39aea60 --- /dev/null +++ b/test/declarative_validation/apps/daemonset/declarative_validation_test.go @@ -0,0 +1,79 @@ +/* +Copyright 2025 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 daemonset + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" + apitesting "k8s.io/kubernetes/pkg/api/testing" + "k8s.io/kubernetes/pkg/apis/apps" + api "k8s.io/kubernetes/pkg/apis/core" + registry "k8s.io/kubernetes/pkg/registry/apps/daemonset" +) + +func mkDaemonSet(tolerations ...api.Toleration) *apps.DaemonSet { + return &apps.DaemonSet{ + ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, + Spec: apps.DaemonSetSpec{ + Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"name": "abc"}}, + UpdateStrategy: apps.DaemonSetUpdateStrategy{Type: apps.OnDeleteDaemonSetStrategyType}, + Template: api.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"name": "abc"}}, + Spec: podtest.MakePodSpec(podtest.SetTolerations(tolerations...)), + }, + }, + } +} + +func TestDeclarativeValidate(t *testing.T) { + for _, apiVersion := range apiVersions { + ctx := genericapirequest.WithRequestInfo(genericapirequest.NewDefaultContext(), &genericapirequest.RequestInfo{ + APIGroup: "apps", + APIVersion: apiVersion, + }) + testCases := map[string]struct { + input *apps.DaemonSet + expectedErrs field.ErrorList + }{ + "valid": { + input: mkDaemonSet(), + }, + "valid toleration key": { + input: mkDaemonSet(api.Toleration{Key: "example.com/valid-key", Operator: api.TolerationOpExists}), + }, + "valid toleration key without prefix": { + input: mkDaemonSet(api.Toleration{Key: "simple-key", Operator: api.TolerationOpExists}), + }, + "invalid toleration key format": { + input: mkDaemonSet(api.Toleration{Key: "invalid key", Operator: api.TolerationOpExists}), + expectedErrs: field.ErrorList{ + field.Invalid(field.NewPath("spec", "template", "spec", "tolerations").Index(0).Child("key"), nil, "").WithOrigin("format=k8s-label-key").MarkAlpha(), + }, + }, + } + for k, tc := range testCases { + t.Run(k, func(t *testing.T) { + apitesting.VerifyValidationEquivalence(t, ctx, tc.input, registry.Strategy, tc.expectedErrs, + apitesting.WithSkipGroupVersions("extensions/v1beta1")) + }) + } + } +} diff --git a/test/declarative_validation/apps/deployment/declarative_validation_test.go b/test/declarative_validation/apps/deployment/declarative_validation_test.go new file mode 100644 index 00000000000..9269af5bcc7 --- /dev/null +++ b/test/declarative_validation/apps/deployment/declarative_validation_test.go @@ -0,0 +1,86 @@ +/* +Copyright 2025 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 deployment + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/intstr" + "k8s.io/apimachinery/pkg/util/validation/field" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" + apitesting "k8s.io/kubernetes/pkg/api/testing" + "k8s.io/kubernetes/pkg/apis/apps" + api "k8s.io/kubernetes/pkg/apis/core" + registry "k8s.io/kubernetes/pkg/registry/apps/deployment" +) + +func mkDeployment(tolerations ...api.Toleration) *apps.Deployment { + return &apps.Deployment{ + ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, + Spec: apps.DeploymentSpec{ + Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"name": "abc"}}, + Strategy: apps.DeploymentStrategy{ + Type: apps.RollingUpdateDeploymentStrategyType, + RollingUpdate: &apps.RollingUpdateDeployment{ + MaxSurge: intstr.FromInt32(1), + MaxUnavailable: intstr.FromInt32(1), + }, + }, + Template: api.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"name": "abc"}}, + Spec: podtest.MakePodSpec(podtest.SetTolerations(tolerations...)), + }, + }, + } +} + +func TestDeclarativeValidate(t *testing.T) { + for _, apiVersion := range apiVersions { + ctx := genericapirequest.WithRequestInfo(genericapirequest.NewDefaultContext(), &genericapirequest.RequestInfo{ + APIGroup: "apps", + APIVersion: apiVersion, + }) + testCases := map[string]struct { + input *apps.Deployment + expectedErrs field.ErrorList + }{ + "valid": { + input: mkDeployment(), + }, + "valid toleration key": { + input: mkDeployment(api.Toleration{Key: "example.com/valid-key", Operator: api.TolerationOpExists}), + }, + "valid toleration key without prefix": { + input: mkDeployment(api.Toleration{Key: "simple-key", Operator: api.TolerationOpExists}), + }, + "invalid toleration key format": { + input: mkDeployment(api.Toleration{Key: "invalid key", Operator: api.TolerationOpExists}), + expectedErrs: field.ErrorList{ + field.Invalid(field.NewPath("spec", "template", "spec", "tolerations").Index(0).Child("key"), nil, "").WithOrigin("format=k8s-label-key").MarkAlpha(), + }, + }, + } + for k, tc := range testCases { + t.Run(k, func(t *testing.T) { + apitesting.VerifyValidationEquivalence(t, ctx, tc.input, registry.Strategy, tc.expectedErrs, + apitesting.WithSkipGroupVersions("extensions/v1beta1")) + }) + } + } +} diff --git a/test/declarative_validation/apps/replicaset/declarative_validation_test.go b/test/declarative_validation/apps/replicaset/declarative_validation_test.go new file mode 100644 index 00000000000..0362294d44b --- /dev/null +++ b/test/declarative_validation/apps/replicaset/declarative_validation_test.go @@ -0,0 +1,78 @@ +/* +Copyright 2025 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 replicaset + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" + apitesting "k8s.io/kubernetes/pkg/api/testing" + "k8s.io/kubernetes/pkg/apis/apps" + api "k8s.io/kubernetes/pkg/apis/core" + registry "k8s.io/kubernetes/pkg/registry/apps/replicaset" +) + +func mkReplicaSet(tolerations ...api.Toleration) *apps.ReplicaSet { + return &apps.ReplicaSet{ + ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, + Spec: apps.ReplicaSetSpec{ + Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"name": "abc"}}, + Template: api.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"name": "abc"}}, + Spec: podtest.MakePodSpec(podtest.SetTolerations(tolerations...)), + }, + }, + } +} + +func TestDeclarativeValidate(t *testing.T) { + for _, apiVersion := range apiVersions { + ctx := genericapirequest.WithRequestInfo(genericapirequest.NewDefaultContext(), &genericapirequest.RequestInfo{ + APIGroup: "apps", + APIVersion: apiVersion, + }) + testCases := map[string]struct { + input *apps.ReplicaSet + expectedErrs field.ErrorList + }{ + "valid": { + input: mkReplicaSet(), + }, + "valid toleration key": { + input: mkReplicaSet(api.Toleration{Key: "example.com/valid-key", Operator: api.TolerationOpExists}), + }, + "valid toleration key without prefix": { + input: mkReplicaSet(api.Toleration{Key: "simple-key", Operator: api.TolerationOpExists}), + }, + "invalid toleration key format": { + input: mkReplicaSet(api.Toleration{Key: "invalid key", Operator: api.TolerationOpExists}), + expectedErrs: field.ErrorList{ + field.Invalid(field.NewPath("spec", "template", "spec", "tolerations").Index(0).Child("key"), nil, "").WithOrigin("format=k8s-label-key").MarkAlpha(), + }, + }, + } + for k, tc := range testCases { + t.Run(k, func(t *testing.T) { + apitesting.VerifyValidationEquivalence(t, ctx, tc.input, registry.Strategy, tc.expectedErrs, + apitesting.WithSkipGroupVersions("extensions/v1beta1")) + }) + } + } +} diff --git a/test/declarative_validation/apps/statefulset/declarative_validation_test.go b/test/declarative_validation/apps/statefulset/declarative_validation_test.go new file mode 100644 index 00000000000..b1addfc40cf --- /dev/null +++ b/test/declarative_validation/apps/statefulset/declarative_validation_test.go @@ -0,0 +1,79 @@ +/* +Copyright 2025 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 statefulset + +import ( + "testing" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/util/validation/field" + genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + podtest "k8s.io/kubernetes/pkg/api/pod/testing" + apitesting "k8s.io/kubernetes/pkg/api/testing" + "k8s.io/kubernetes/pkg/apis/apps" + api "k8s.io/kubernetes/pkg/apis/core" + registry "k8s.io/kubernetes/pkg/registry/apps/statefulset" +) + +func mkStatefulSet(tolerations ...api.Toleration) *apps.StatefulSet { + return &apps.StatefulSet{ + ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, + Spec: apps.StatefulSetSpec{ + PodManagementPolicy: apps.OrderedReadyPodManagement, + Selector: &metav1.LabelSelector{MatchLabels: map[string]string{"a": "b"}}, + UpdateStrategy: apps.StatefulSetUpdateStrategy{Type: apps.RollingUpdateStatefulSetStrategyType}, + Template: api.PodTemplateSpec{ + ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"a": "b"}}, + Spec: podtest.MakePodSpec(podtest.SetTolerations(tolerations...)), + }, + }, + } +} + +func TestDeclarativeValidate(t *testing.T) { + for _, apiVersion := range apiVersions { + ctx := genericapirequest.WithRequestInfo(genericapirequest.NewDefaultContext(), &genericapirequest.RequestInfo{ + APIGroup: "apps", + APIVersion: apiVersion, + }) + testCases := map[string]struct { + input *apps.StatefulSet + expectedErrs field.ErrorList + }{ + "valid": { + input: mkStatefulSet(), + }, + "valid toleration key": { + input: mkStatefulSet(api.Toleration{Key: "example.com/valid-key", Operator: api.TolerationOpExists}), + }, + "valid toleration key without prefix": { + input: mkStatefulSet(api.Toleration{Key: "simple-key", Operator: api.TolerationOpExists}), + }, + "invalid toleration key format": { + input: mkStatefulSet(api.Toleration{Key: "invalid key", Operator: api.TolerationOpExists}), + expectedErrs: field.ErrorList{ + field.Invalid(field.NewPath("spec", "template", "spec", "tolerations").Index(0).Child("key"), nil, "").WithOrigin("format=k8s-label-key").MarkAlpha(), + }, + }, + } + for k, tc := range testCases { + t.Run(k, func(t *testing.T) { + apitesting.VerifyValidationEquivalence(t, ctx, tc.input, registry.Strategy, tc.expectedErrs) + }) + } + } +} From fd8870da0956e778807e2764259099fd14ed9f8a Mon Sep 17 00:00:00 2001 From: Yongrui Lin Date: Tue, 9 Jun 2026 20:56:55 +0000 Subject: [PATCH 09/10] batch: add declarative validation tests for toleration key Job and CronJob; prefixed and unprefixed keys. --- .../cronjob/declarative_validation_test.go | 18 ++++++++++++++++ .../batch/job/declarative_validation_test.go | 21 +++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/test/declarative_validation/batch/cronjob/declarative_validation_test.go b/test/declarative_validation/batch/cronjob/declarative_validation_test.go index 17d0937c541..cf166e23767 100644 --- a/test/declarative_validation/batch/cronjob/declarative_validation_test.go +++ b/test/declarative_validation/batch/cronjob/declarative_validation_test.go @@ -66,6 +66,18 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) { tweakJobTemplateBackoffLimitPerIndex(ptr.To[int32](1)), ), }, + "tolerations: valid key": { + input: mkCronJob(tweakTolerations(api.Toleration{Key: "example.com/valid-key", Operator: api.TolerationOpExists})), + }, + "tolerations: valid key without prefix": { + input: mkCronJob(tweakTolerations(api.Toleration{Key: "simple-key", Operator: api.TolerationOpExists})), + }, + "tolerations: invalid key format": { + input: mkCronJob(tweakTolerations(api.Toleration{Key: "invalid key", Operator: api.TolerationOpExists})), + expectedErrs: field.ErrorList{ + field.Invalid(field.NewPath("spec", "jobTemplate", "spec", "template", "spec", "tolerations").Index(0).Child("key"), nil, "").WithOrigin("format=k8s-label-key").MarkAlpha(), + }, + }, } for k, tc := range testCases { t.Run(k, func(t *testing.T) { @@ -146,6 +158,12 @@ func tweakJobTemplateBackoffLimitPerIndex(v *int32) func(*batch.CronJob) { } } +func tweakTolerations(tolerations ...api.Toleration) func(*batch.CronJob) { + return func(job *batch.CronJob) { + job.Spec.JobTemplate.Spec.Template.Spec.Tolerations = tolerations + } +} + var validCronjobSpec = batch.CronJobSpec{ Schedule: "5 5 * * ?", ConcurrencyPolicy: batch.AllowConcurrent, diff --git a/test/declarative_validation/batch/job/declarative_validation_test.go b/test/declarative_validation/batch/job/declarative_validation_test.go index 72c7d9bf9c4..23b7ccd705f 100644 --- a/test/declarative_validation/batch/job/declarative_validation_test.go +++ b/test/declarative_validation/batch/job/declarative_validation_test.go @@ -46,6 +46,9 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) { input batch.Job expectedErrs field.ErrorList }{ + "valid": { + input: mkJob(), + }, "maxFailedIndexes and backoffLimitPerIndex both set": { input: mkJob( tweakMaxFailedIndexes(ptr.To[int32](5)), @@ -58,6 +61,18 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) { field.Required(field.NewPath("spec", "backoffLimitPerIndex"), "").WithOrigin("dependentRequired").MarkAlpha(), }, }, + "valid toleration key": { + input: mkJob(tweakTolerations(api.Toleration{Key: "example.com/valid-key", Operator: api.TolerationOpExists})), + }, + "valid toleration key without prefix": { + input: mkJob(tweakTolerations(api.Toleration{Key: "simple-key", Operator: api.TolerationOpExists})), + }, + "invalid toleration key format": { + input: mkJob(tweakTolerations(api.Toleration{Key: "invalid key", Operator: api.TolerationOpExists})), + expectedErrs: field.ErrorList{ + field.Invalid(field.NewPath("spec", "template", "spec", "tolerations").Index(0).Child("key"), nil, "").WithOrigin("format=k8s-label-key").MarkAlpha(), + }, + }, } for k, tc := range testCases { t.Run(k, func(t *testing.T) { @@ -93,6 +108,12 @@ func tweakBackoffLimitPerIndex(v *int32) func(*batch.Job) { } } +func tweakTolerations(tolerations ...api.Toleration) func(*batch.Job) { + return func(job *batch.Job) { + job.Spec.Template.Spec.Tolerations = tolerations + } +} + var validJobLabels = map[string]string{ batch.ControllerUidLabel: "1a2b3c", batch.LegacyControllerUidLabel: "1a2b3c", From 462aa20ad9bde04ca9e33a7cb1074cc91dd26a03 Mon Sep 17 00:00:00 2001 From: Yongrui Lin Date: Tue, 9 Jun 2026 20:56:55 +0000 Subject: [PATCH 10/10] node: add declarative validation tests for toleration key RuntimeClass across v1, v1alpha1, and v1beta1; prefixed and unprefixed keys. --- .../declarative_validation_test.go | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/test/declarative_validation/node/runtimeclass/declarative_validation_test.go b/test/declarative_validation/node/runtimeclass/declarative_validation_test.go index 87691520d90..5237451180e 100644 --- a/test/declarative_validation/node/runtimeclass/declarative_validation_test.go +++ b/test/declarative_validation/node/runtimeclass/declarative_validation_test.go @@ -23,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" apitesting "k8s.io/kubernetes/pkg/api/testing" + api "k8s.io/kubernetes/pkg/apis/core" node "k8s.io/kubernetes/pkg/apis/node" "k8s.io/kubernetes/pkg/apis/node/validation" registry "k8s.io/kubernetes/pkg/registry/node/runtimeclass" @@ -97,6 +98,32 @@ func TestRuntimeClass_DeclarativeValidate_Create(t *testing.T) { "", "").WithOrigin("format=k8s-short-name").MarkAlpha(), }, }, + "scheduling toleration with valid key": { + obj: mkRuntimeClassHandlerOnly(func(rc *node.RuntimeClass) { + rc.Scheduling = &node.Scheduling{ + Tolerations: []api.Toleration{{Key: "example.com/valid-key", Operator: api.TolerationOpExists}}, + } + }), + expectedErrs: field.ErrorList{}, + }, + "scheduling toleration with valid key without prefix": { + obj: mkRuntimeClassHandlerOnly(func(rc *node.RuntimeClass) { + rc.Scheduling = &node.Scheduling{ + Tolerations: []api.Toleration{{Key: "simple-key", Operator: api.TolerationOpExists}}, + } + }), + expectedErrs: field.ErrorList{}, + }, + "scheduling toleration with invalid key format": { + obj: mkRuntimeClassHandlerOnly(func(rc *node.RuntimeClass) { + rc.Scheduling = &node.Scheduling{ + Tolerations: []api.Toleration{{Key: "invalid key", Operator: api.TolerationOpExists}}, + } + }), + expectedErrs: field.ErrorList{ + field.Invalid(field.NewPath("scheduling", "tolerations").Index(0).Child("key"), nil, "").WithOrigin("format=k8s-label-key").MarkAlpha(), + }, + }, } for name, tc := range tests {