Merge pull request #139562 from yongruilin/dv-podspec-toleration

Add declarative validation for Toleration key format
This commit is contained in:
Kubernetes Prow Robot 2026-06-11 23:10:42 +05:30 committed by GitHub
commit 66ad1618f1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
65 changed files with 2855 additions and 434 deletions

View file

@ -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.

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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

View file

@ -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
}

View file

@ -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 {

View file

@ -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
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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 {

View file

@ -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.

View file

@ -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:""`

View file

@ -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

View file

@ -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:""`

View file

@ -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

View file

@ -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:""`

View file

@ -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.

View file

@ -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.
@ -5492,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.
@ -5616,6 +5621,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"`
}

View file

@ -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

View file

@ -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
}

View file

@ -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;
}

View file

@ -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"`
}

View file

@ -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;
}

View file

@ -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"`
}

View file

@ -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;
}

View file

@ -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"`
}

View file

@ -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"))
})
}
}
}

View file

@ -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)
}

View file

@ -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"},
},
},
)
}

View file

@ -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"},
},
},
)
}

View file

@ -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"))
})
}
}
}

View file

@ -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)
}

View file

@ -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"},
},
},
)
}

View file

@ -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"},
},
},
)
}

View file

@ -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"},
},
},
)
}

View file

@ -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"))
})
}
}
}

View file

@ -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)
}

View file

@ -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"},
},
},
)
}

View file

@ -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"},
},
},
)
}

View file

@ -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"))
})
}
})

View file

@ -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)
})
}
}
}

View file

@ -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)
}

View file

@ -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"},
},
},
)
}

View file

@ -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"},
},
},
)
}

View file

@ -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"},
},
},
)
}

View file

@ -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"))
})
}
})

View file

@ -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,

View file

@ -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"},
},

View file

@ -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"},
},

View file

@ -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",

View file

@ -33,6 +33,9 @@ func init() {
"spec.backoffLimitPerIndex": {
{ErrorType: "FieldValueRequired", Origin: "dependentRequired"},
},
"spec.template.spec.tolerations[*].key": {
{ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"},
},
},
)
}

View file

@ -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)
})
}
}
}

View file

@ -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)
}

View file

@ -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"},
},
},
)
}

View file

@ -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)
})
}
}
}

View file

@ -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)
}

View file

@ -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"},
},
},
)
}

View file

@ -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
}
}

View file

@ -40,6 +40,9 @@ func init() {
{ErrorType: "FieldValueInvalid", Origin: "minimum"},
{ErrorType: "FieldValueRequired"},
},
"spec.template.spec.tolerations[*].key": {
{ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"},
},
},
)
}

View file

@ -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"),
)
})
}

View file

@ -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 {

View file

@ -35,6 +35,9 @@ func init() {
{ErrorType: "FieldValueInvalid", Origin: "immutable"},
{ErrorType: "FieldValueRequired"},
},
"scheduling.tolerations[*].key": {
{ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"},
},
},
)
}

View file

@ -35,6 +35,9 @@ func init() {
{ErrorType: "FieldValueInvalid", Origin: "immutable"},
{ErrorType: "FieldValueRequired"},
},
"spec.scheduling.tolerations[*].key": {
{ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"},
},
},
)
}

View file

@ -35,6 +35,9 @@ func init() {
{ErrorType: "FieldValueInvalid", Origin: "immutable"},
{ErrorType: "FieldValueRequired"},
},
"scheduling.tolerations[*].key": {
{ErrorType: "FieldValueInvalid", Origin: "format=k8s-label-key"},
},
},
)
}