diff --git a/pkg/registry/admissionregistration/mutatingadmissionpolicy/strategy.go b/pkg/registry/admissionregistration/mutatingadmissionpolicy/strategy.go index f413e9fc4f6..8e6302399b8 100644 --- a/pkg/registry/admissionregistration/mutatingadmissionpolicy/strategy.go +++ b/pkg/registry/admissionregistration/mutatingadmissionpolicy/strategy.go @@ -24,6 +24,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/features" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -34,7 +35,7 @@ import ( // mutatingAdmissionPolicyStrategy implements verification logic for MutatingAdmissionPolicy. type mutatingAdmissionPolicyStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator authorizer authorizer.Authorizer resourceResolver resolver.ResourceResolver @@ -43,7 +44,7 @@ type mutatingAdmissionPolicyStrategy struct { // NewStrategy is the default logic that applies when creating and updating MutatingAdmissionPolicy objects. func NewStrategy(authorizer authorizer.Authorizer, resourceResolver resolver.ResourceResolver) *mutatingAdmissionPolicyStrategy { return &mutatingAdmissionPolicyStrategy{ - ObjectTyper: legacyscheme.Scheme, + DeclarativeValidation: rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, NameGenerator: names.SimpleNameGenerator, authorizer: authorizer, resourceResolver: resourceResolver, diff --git a/pkg/registry/admissionregistration/mutatingadmissionpolicybinding/strategy.go b/pkg/registry/admissionregistration/mutatingadmissionpolicybinding/strategy.go index 575515b1617..a854264ee5f 100644 --- a/pkg/registry/admissionregistration/mutatingadmissionpolicybinding/strategy.go +++ b/pkg/registry/admissionregistration/mutatingadmissionpolicybinding/strategy.go @@ -24,6 +24,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/features" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -34,7 +35,7 @@ import ( // MutatingAdmissionPolicyBindingStrategy implements verification logic for MutatingAdmissionPolicyBinding. type mutatingAdmissionPolicyBindingStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator authorizer authorizer.Authorizer policyGetter PolicyGetter @@ -50,7 +51,7 @@ type PolicyGetter interface { // NewStrategy is the default logic that applies when creating and updating MutatingAdmissionPolicyBinding objects. func NewStrategy(authorizer authorizer.Authorizer, policyGetter PolicyGetter, resourceResolver resolver.ResourceResolver) *mutatingAdmissionPolicyBindingStrategy { return &mutatingAdmissionPolicyBindingStrategy{ - ObjectTyper: legacyscheme.Scheme, + DeclarativeValidation: rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, NameGenerator: names.SimpleNameGenerator, authorizer: authorizer, policyGetter: policyGetter, diff --git a/pkg/registry/admissionregistration/mutatingwebhookconfiguration/strategy.go b/pkg/registry/admissionregistration/mutatingwebhookconfiguration/strategy.go index 52e2cbea4aa..4762b9853d3 100644 --- a/pkg/registry/admissionregistration/mutatingwebhookconfiguration/strategy.go +++ b/pkg/registry/admissionregistration/mutatingwebhookconfiguration/strategy.go @@ -23,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/features" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -32,12 +33,12 @@ import ( // mutatingWebhookConfigurationStrategy implements verification logic for mutatingWebhookConfiguration. type mutatingWebhookConfigurationStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating mutatingWebhookConfiguration objects. -var Strategy = mutatingWebhookConfigurationStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = mutatingWebhookConfigurationStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped returns false because MutatingWebhookConfiguration is cluster-scoped resource. func (mutatingWebhookConfigurationStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/admissionregistration/validatingadmissionpolicy/strategy.go b/pkg/registry/admissionregistration/validatingadmissionpolicy/strategy.go index ce707d1074e..189143e32c6 100644 --- a/pkg/registry/admissionregistration/validatingadmissionpolicy/strategy.go +++ b/pkg/registry/admissionregistration/validatingadmissionpolicy/strategy.go @@ -27,6 +27,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/features" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -37,7 +38,7 @@ import ( // validatingAdmissionPolicyStrategy implements verification logic for ValidatingAdmissionPolicy. type validatingAdmissionPolicyStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator authorizer authorizer.Authorizer resourceResolver resolver.ResourceResolver @@ -46,7 +47,7 @@ type validatingAdmissionPolicyStrategy struct { // NewStrategy is the default logic that applies when creating and updating validatingAdmissionPolicy objects. func NewStrategy(authorizer authorizer.Authorizer, resourceResolver resolver.ResourceResolver) *validatingAdmissionPolicyStrategy { return &validatingAdmissionPolicyStrategy{ - ObjectTyper: legacyscheme.Scheme, + DeclarativeValidation: rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, NameGenerator: names.SimpleNameGenerator, authorizer: authorizer, resourceResolver: resourceResolver, diff --git a/pkg/registry/admissionregistration/validatingadmissionpolicybinding/declarative_validation_test.go b/pkg/registry/admissionregistration/validatingadmissionpolicybinding/declarative_validation_test.go index 5b816ec23d1..4a548b8ee17 100644 --- a/pkg/registry/admissionregistration/validatingadmissionpolicybinding/declarative_validation_test.go +++ b/pkg/registry/admissionregistration/validatingadmissionpolicybinding/declarative_validation_test.go @@ -67,7 +67,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) { } for k, tc := range testCases { t.Run(k, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, &Strategy, tc.expectedErrs) }) } } @@ -117,7 +117,7 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) { IsResourceRequest: true, Verb: "update", }) - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, Strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, &Strategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/admissionregistration/validatingadmissionpolicybinding/strategy.go b/pkg/registry/admissionregistration/validatingadmissionpolicybinding/strategy.go index c8fe6897be4..187b387427c 100644 --- a/pkg/registry/admissionregistration/validatingadmissionpolicybinding/strategy.go +++ b/pkg/registry/admissionregistration/validatingadmissionpolicybinding/strategy.go @@ -18,7 +18,6 @@ package validatingadmissionpolicybinding import ( "context" - "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apiserver/pkg/registry/rest" apiequality "k8s.io/apimachinery/pkg/api/equality" @@ -36,7 +35,7 @@ import ( // validatingAdmissionPolicyBindingStrategy implements verification logic for ValidatingAdmissionPolicyBinding. type validatingAdmissionPolicyBindingStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator authorizer authorizer.Authorizer policyGetter PolicyGetter @@ -54,7 +53,7 @@ type PolicyGetter interface { // NewStrategy is the default logic that applies when creating and updating ValidatingAdmissionPolicyBinding objects. func NewStrategy(authorizer authorizer.Authorizer, policyGetter PolicyGetter, resourceResolver resolver.ResourceResolver) *validatingAdmissionPolicyBindingStrategy { return &validatingAdmissionPolicyBindingStrategy{ - ObjectTyper: legacyscheme.Scheme, + DeclarativeValidation: rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, NameGenerator: names.SimpleNameGenerator, authorizer: authorizer, policyGetter: policyGetter, @@ -99,7 +98,7 @@ func (v *validatingAdmissionPolicyBindingStrategy) Validate(ctx context.Context, errs = append(errs, field.Forbidden(field.NewPath("spec", "paramRef"), err.Error())) } } - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, nil, errs, operation.Create) + return errs } // WarningsOnCreate returns warnings for the creation of the given object. @@ -131,7 +130,7 @@ func (v *validatingAdmissionPolicyBindingStrategy) ValidateUpdate(ctx context.Co errs = append(errs, field.Forbidden(field.NewPath("spec", "paramRef"), err.Error())) } } - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, old, errs, operation.Update) + return errs } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/admissionregistration/validatingwebhookconfiguration/strategy.go b/pkg/registry/admissionregistration/validatingwebhookconfiguration/strategy.go index d206d36bf6c..26ca0442f10 100644 --- a/pkg/registry/admissionregistration/validatingwebhookconfiguration/strategy.go +++ b/pkg/registry/admissionregistration/validatingwebhookconfiguration/strategy.go @@ -23,6 +23,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/features" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -32,12 +33,12 @@ import ( // validatingWebhookConfigurationStrategy implements verification logic for validatingWebhookConfiguration. type validatingWebhookConfigurationStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating validatingWebhookConfiguration objects. -var Strategy = validatingWebhookConfigurationStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = validatingWebhookConfigurationStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped returns false because ValidatingWebhookConfiguration is cluster-scoped resource. func (validatingWebhookConfigurationStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/apiserverinternal/storageversion/strategy.go b/pkg/registry/apiserverinternal/storageversion/strategy.go index 18a12a762f0..4a887a15139 100644 --- a/pkg/registry/apiserverinternal/storageversion/strategy.go +++ b/pkg/registry/apiserverinternal/storageversion/strategy.go @@ -22,6 +22,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/apiserverinternal" @@ -31,12 +32,12 @@ import ( // storageVersionStrategy implements verification logic for StorageVersion. type storageVersionStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating StorageVersion objects. -var Strategy = storageVersionStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = storageVersionStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped returns false because all StorageVersion's need to be cluster scoped func (storageVersionStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/apps/controllerrevision/strategy.go b/pkg/registry/apps/controllerrevision/strategy.go index c0b9d680990..e66b5286370 100644 --- a/pkg/registry/apps/controllerrevision/strategy.go +++ b/pkg/registry/apps/controllerrevision/strategy.go @@ -30,13 +30,13 @@ import ( // strategy implements behavior for ConfigMap objects type strategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating ControllerRevision // objects via the REST API. -var Strategy = strategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = strategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // Strategy should implement rest.RESTCreateStrategy var _ rest.RESTCreateStrategy = Strategy diff --git a/pkg/registry/apps/daemonset/strategy.go b/pkg/registry/apps/daemonset/strategy.go index 00778b817dd..30fe480010f 100644 --- a/pkg/registry/apps/daemonset/strategy.go +++ b/pkg/registry/apps/daemonset/strategy.go @@ -34,12 +34,12 @@ import ( // daemonSetStrategy implements verification logic for daemon sets. type daemonSetStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating DaemonSet objects. -var Strategy = daemonSetStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = daemonSetStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // Make sure we correctly implement the interface. var _ = rest.GarbageCollectionDeleteStrategy(Strategy) diff --git a/pkg/registry/apps/deployment/strategy.go b/pkg/registry/apps/deployment/strategy.go index 98f9db112d3..02c9e6b18de 100644 --- a/pkg/registry/apps/deployment/strategy.go +++ b/pkg/registry/apps/deployment/strategy.go @@ -37,13 +37,13 @@ import ( // deploymentStrategy implements behavior for Deployments. type deploymentStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Deployment // objects via the REST API. -var Strategy = deploymentStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = deploymentStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // Make sure we correctly implement the interface. var _ = rest.GarbageCollectionDeleteStrategy(Strategy) diff --git a/pkg/registry/apps/replicaset/strategy.go b/pkg/registry/apps/replicaset/strategy.go index ede541ca7d0..d30ae81f896 100644 --- a/pkg/registry/apps/replicaset/strategy.go +++ b/pkg/registry/apps/replicaset/strategy.go @@ -44,12 +44,12 @@ import ( // rsStrategy implements verification logic for ReplicaSets. type rsStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating ReplicaSet objects. -var Strategy = rsStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = rsStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // Make sure we correctly implement the interface. var _ = rest.GarbageCollectionDeleteStrategy(Strategy) diff --git a/pkg/registry/apps/statefulset/strategy.go b/pkg/registry/apps/statefulset/strategy.go index ed33e5eeadb..aecedb41d39 100644 --- a/pkg/registry/apps/statefulset/strategy.go +++ b/pkg/registry/apps/statefulset/strategy.go @@ -36,12 +36,12 @@ import ( // statefulSetStrategy implements verification logic for Replication StatefulSets. type statefulSetStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Replication StatefulSet objects. -var Strategy = statefulSetStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = statefulSetStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // Make sure we correctly implement the interface. var _ = rest.GarbageCollectionDeleteStrategy(Strategy) diff --git a/pkg/registry/autoscaling/horizontalpodautoscaler/declarative_validation_test.go b/pkg/registry/autoscaling/horizontalpodautoscaler/declarative_validation_test.go index 8590012ddd4..cffb8d7b808 100644 --- a/pkg/registry/autoscaling/horizontalpodautoscaler/declarative_validation_test.go +++ b/pkg/registry/autoscaling/horizontalpodautoscaler/declarative_validation_test.go @@ -82,7 +82,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.HPAScaleToZero, tc.enableScaleToZero) - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs) }) } } @@ -153,7 +153,7 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) { IsResourceRequest: true, Verb: "update", }) - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, Strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, Strategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/autoscaling/horizontalpodautoscaler/strategy.go b/pkg/registry/autoscaling/horizontalpodautoscaler/strategy.go index ce7f8a2dd62..f2860c10b93 100644 --- a/pkg/registry/autoscaling/horizontalpodautoscaler/strategy.go +++ b/pkg/registry/autoscaling/horizontalpodautoscaler/strategy.go @@ -20,7 +20,6 @@ import ( "context" apiequality "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/rest" @@ -35,13 +34,13 @@ import ( // autoscalerStrategy implements behavior for HorizontalPodAutoscalers type autoscalerStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating HorizontalPodAutoscaler // objects via the REST API. -var Strategy = autoscalerStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = autoscalerStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped is true for autoscaler. func (autoscalerStrategy) NamespaceScoped() bool { @@ -82,12 +81,27 @@ func (autoscalerStrategy) PrepareForCreate(ctx context.Context, obj runtime.Obje func (autoscalerStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { autoscaler := obj.(*autoscaling.HorizontalPodAutoscaler) opts := validationOptionsForHorizontalPodAutoscaler(autoscaler, nil) - allErrs := validation.ValidateHorizontalPodAutoscaler(autoscaler, opts) + return validation.ValidateHorizontalPodAutoscaler(autoscaler, opts) +} + +// DeclarativeValidationConfig implements rest.DeclarativeValidationConfigurer to supply declarative +// validation options. +func (autoscalerStrategy) DeclarativeValidationConfig(ctx context.Context, obj, oldObj runtime.Object) rest.DeclarativeValidationConfig { var options []string - if utilfeature.DefaultFeatureGate.Enabled(features.HPAScaleToZero) { + // Pass HPAScaleToZero when the gate is enabled, OR (on update) when the + // existing object already has MinReplicas == 0. + enableScaleToZero := utilfeature.DefaultFeatureGate.Enabled(features.HPAScaleToZero) + if !enableScaleToZero && oldObj != nil { + if oldHPA, ok := oldObj.(*autoscaling.HorizontalPodAutoscaler); ok { + if oldHPA.Spec.MinReplicas != nil && *oldHPA.Spec.MinReplicas == 0 { + enableScaleToZero = true + } + } + } + if enableScaleToZero { options = append(options, "HPAScaleToZero") } - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, autoscaler, nil, allErrs, operation.Create, rest.WithOptions(options)) + return rest.DeclarativeValidationConfig{Options: options} } // WarningsOnCreate returns warnings for the creation of the given object. @@ -125,13 +139,7 @@ func (autoscalerStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.O newHPA := obj.(*autoscaling.HorizontalPodAutoscaler) oldHPA := old.(*autoscaling.HorizontalPodAutoscaler) opts := validationOptionsForHorizontalPodAutoscaler(newHPA, oldHPA) - errs := validation.ValidateHorizontalPodAutoscalerUpdate(newHPA, oldHPA, opts) - var options []string - oldHasZeroMinReplicas := oldHPA.Spec.MinReplicas != nil && *oldHPA.Spec.MinReplicas == 0 - if utilfeature.DefaultFeatureGate.Enabled(features.HPAScaleToZero) || oldHasZeroMinReplicas { - options = append(options, "HPAScaleToZero") - } - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newHPA, oldHPA, errs, operation.Update, rest.WithOptions(options)) + return validation.ValidateHorizontalPodAutoscalerUpdate(newHPA, oldHPA, opts) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/batch/cronjob/declarative_validation_test.go b/pkg/registry/batch/cronjob/declarative_validation_test.go index 85e4ffba474..0cd48c07edf 100644 --- a/pkg/registry/batch/cronjob/declarative_validation_test.go +++ b/pkg/registry/batch/cronjob/declarative_validation_test.go @@ -55,7 +55,7 @@ func testDeclarativeValidateForDeclarative(t *testing.T, apiVersion string) { } for k, tc := range testCases { t.Run(k, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs) }) } } @@ -93,7 +93,7 @@ func testValidateUpdateForDeclarative(t *testing.T, apiVersion string) { t.Run(k, func(t *testing.T) { tc.old.ResourceVersion = "1" tc.update.ResourceVersion = "2" - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, Strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, Strategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/batch/cronjob/strategy.go b/pkg/registry/batch/cronjob/strategy.go index 50075094bc2..6e3a8db435e 100644 --- a/pkg/registry/batch/cronjob/strategy.go +++ b/pkg/registry/batch/cronjob/strategy.go @@ -23,7 +23,6 @@ import ( batchv1beta1 "k8s.io/api/batch/v1beta1" apiequality "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" utilvalidation "k8s.io/apimachinery/pkg/util/validation" @@ -41,12 +40,12 @@ import ( // cronJobStrategy implements verification logic for Replication Controllers. type cronJobStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating CronJob objects. -var Strategy = cronJobStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = cronJobStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // DefaultGarbageCollectionPolicy returns OrphanDependents for batch/v1beta1 for backwards compatibility, // and DeleteDependents for all other versions. @@ -113,8 +112,7 @@ func (cronJobStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Ob func (cronJobStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { cronJob := obj.(*batch.CronJob) opts := pod.GetValidationOptionsFromPodTemplate(&cronJob.Spec.JobTemplate.Spec.Template, nil) - allErrs := batchvalidation.ValidateCronJobCreate(cronJob, opts) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, nil, allErrs, operation.Create) + return batchvalidation.ValidateCronJobCreate(cronJob, opts) } // WarningsOnCreate returns warnings for the creation of the given object. @@ -147,8 +145,7 @@ func (cronJobStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Obje oldCronJob := old.(*batch.CronJob) opts := pod.GetValidationOptionsFromPodTemplate(&newCronJob.Spec.JobTemplate.Spec.Template, &oldCronJob.Spec.JobTemplate.Spec.Template) - allErrs := batchvalidation.ValidateCronJobUpdate(newCronJob, oldCronJob, opts) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newCronJob, oldCronJob, allErrs, operation.Update) + return batchvalidation.ValidateCronJobUpdate(newCronJob, oldCronJob, opts) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/batch/job/strategy.go b/pkg/registry/batch/job/strategy.go index a24f88fc7a6..d64643d690e 100644 --- a/pkg/registry/batch/job/strategy.go +++ b/pkg/registry/batch/job/strategy.go @@ -50,12 +50,12 @@ import ( // jobStrategy implements verification logic for Replication Controllers. type jobStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Replication Controller objects. -var Strategy = jobStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = jobStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // DefaultGarbageCollectionPolicy returns OrphanDependents for batch/v1 for backwards compatibility, // and DeleteDependents for all other versions. diff --git a/pkg/registry/certificates/certificates/declarative_validation_test.go b/pkg/registry/certificates/certificates/declarative_validation_test.go index ce2b8f885ab..db09fb8b8cd 100644 --- a/pkg/registry/certificates/certificates/declarative_validation_test.go +++ b/pkg/registry/certificates/certificates/declarative_validation_test.go @@ -26,9 +26,9 @@ import ( "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" apitesting "k8s.io/kubernetes/pkg/api/testing" api "k8s.io/kubernetes/pkg/apis/certificates" "k8s.io/kubernetes/pkg/apis/core" @@ -37,11 +37,6 @@ import ( var apiVersions = []string{"v1", "v1beta1"} -type validationStrategy interface { - Validate(ctx context.Context, obj runtime.Object) field.ErrorList - ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList -} - func TestDeclarativeValidateForDeclarative(t *testing.T) { for _, apiVersion := range apiVersions { testDeclarativeValidateForDeclarative(t, apiVersion) @@ -90,7 +85,7 @@ func testDeclarativeValidateForDeclarative(t *testing.T, apiVersion string) { } for k, tc := range testCases { t.Run(k, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs) }) } } @@ -188,7 +183,7 @@ func testValidateUpdateForDeclarative(t *testing.T, apiVersion string) { for _, subresource := range tc.subresources { t.Run(k+" subresource="+subresource, func(t *testing.T) { ctx := createContextForSubresource(apiVersion, subresource) - var strategy validationStrategy + var strategy rest.RESTUpdateStrategy switch subresource { case "/": strategy = Strategy @@ -200,7 +195,7 @@ func testValidateUpdateForDeclarative(t *testing.T, apiVersion string) { tc.old.ResourceVersion = "1" tc.update.ResourceVersion = "1" - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, strategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/certificates/certificates/strategy.go b/pkg/registry/certificates/certificates/strategy.go index 6954100415b..807f6f934ff 100644 --- a/pkg/registry/certificates/certificates/strategy.go +++ b/pkg/registry/certificates/certificates/strategy.go @@ -20,7 +20,6 @@ import ( "context" "fmt" - "k8s.io/apimachinery/pkg/api/operation" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" @@ -38,13 +37,13 @@ import ( // csrStrategy implements behavior for CSRs type csrStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // csrStrategy is the default logic that applies when creating and updating // CSR objects. -var Strategy = csrStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = csrStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped is false for CSRs. func (csrStrategy) NamespaceScoped() bool { @@ -114,8 +113,7 @@ func (csrStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object // Validate validates a new CSR. Validation must check for a correct signature. func (csrStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { csr := obj.(*certificates.CertificateSigningRequest) - allErrs := validation.ValidateCertificateSigningRequestCreate(csr) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, csr, nil, allErrs, operation.Create) + return validation.ValidateCertificateSigningRequestCreate(csr) } // WarningsOnCreate returns warnings for the creation of the given object. @@ -128,8 +126,7 @@ func (csrStrategy) Canonicalize(obj runtime.Object) {} func (csrStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { oldCSR := old.(*certificates.CertificateSigningRequest) newCSR := obj.(*certificates.CertificateSigningRequest) - errs := validation.ValidateCertificateSigningRequestUpdate(newCSR, oldCSR) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newCSR, oldCSR, errs, operation.Update) + return validation.ValidateCertificateSigningRequestUpdate(newCSR, oldCSR) } // WarningsOnUpdate returns warnings for the given update. @@ -244,8 +241,7 @@ func populateConditionTimestamps(newCSR, oldCSR *certificates.CertificateSigning func (csrStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { newCSR := obj.(*certificates.CertificateSigningRequest) oldCSR := old.(*certificates.CertificateSigningRequest) - errs := validation.ValidateCertificateSigningRequestStatusUpdate(newCSR, oldCSR) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newCSR, oldCSR, errs, operation.Update) + return validation.ValidateCertificateSigningRequestStatusUpdate(newCSR, oldCSR) } // WarningsOnUpdate returns warnings for the given update. @@ -299,8 +295,7 @@ func (csrApprovalStrategy) PrepareForUpdate(ctx context.Context, obj, old runtim func (csrApprovalStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { newCSR := obj.(*certificates.CertificateSigningRequest) oldCSR := old.(*certificates.CertificateSigningRequest) - errs := validation.ValidateCertificateSigningRequestApprovalUpdate(newCSR, oldCSR) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newCSR, oldCSR, errs, operation.Update) + return validation.ValidateCertificateSigningRequestApprovalUpdate(newCSR, oldCSR) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/certificates/clustertrustbundle/strategy.go b/pkg/registry/certificates/clustertrustbundle/strategy.go index e334e36db67..542c83ef793 100644 --- a/pkg/registry/certificates/clustertrustbundle/strategy.go +++ b/pkg/registry/certificates/clustertrustbundle/strategy.go @@ -32,12 +32,12 @@ import ( // strategy implements behavior for ClusterTrustBundles. type strategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the create, update, and delete strategy for ClusterTrustBundles. -var Strategy = strategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = strategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} var _ rest.RESTCreateStrategy = Strategy var _ rest.RESTUpdateStrategy = Strategy diff --git a/pkg/registry/certificates/podcertificaterequest/strategy.go b/pkg/registry/certificates/podcertificaterequest/strategy.go index 0fec66de62f..28478189406 100644 --- a/pkg/registry/certificates/podcertificaterequest/strategy.go +++ b/pkg/registry/certificates/podcertificaterequest/strategy.go @@ -41,7 +41,7 @@ import ( // strategy implements behavior for PodCertificateRequests. type Strategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } @@ -51,8 +51,8 @@ var _ rest.RESTDeleteStrategy = (*Strategy)(nil) func NewStrategy() *Strategy { return &Strategy{ - ObjectTyper: legacyscheme.Scheme, - NameGenerator: names.SimpleNameGenerator, + DeclarativeValidation: rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, + NameGenerator: names.SimpleNameGenerator, } } diff --git a/pkg/registry/coordination/lease/strategy.go b/pkg/registry/coordination/lease/strategy.go index 2af5cf460e3..412a2e1ba5e 100644 --- a/pkg/registry/coordination/lease/strategy.go +++ b/pkg/registry/coordination/lease/strategy.go @@ -21,6 +21,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -31,12 +32,12 @@ import ( // leaseStrategy implements verification logic for Leases. type leaseStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Lease objects. -var Strategy = leaseStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = leaseStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped returns true because all Lease' need to be within a namespace. func (leaseStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/coordination/leasecandidate/strategy.go b/pkg/registry/coordination/leasecandidate/strategy.go index 2d5b07e2864..a5a2d58630b 100644 --- a/pkg/registry/coordination/leasecandidate/strategy.go +++ b/pkg/registry/coordination/leasecandidate/strategy.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -34,12 +35,12 @@ import ( // LeaseCandidateStrategy implements verification logic for leasecandidates. type LeaseCandidateStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating leasecandidate objects. -var Strategy = LeaseCandidateStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = LeaseCandidateStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped returns true because all leasecandidate' need to be within a namespace. func (LeaseCandidateStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/core/configmap/strategy.go b/pkg/registry/core/configmap/strategy.go index c85e115cbf3..4712f1590cf 100644 --- a/pkg/registry/core/configmap/strategy.go +++ b/pkg/registry/core/configmap/strategy.go @@ -35,13 +35,13 @@ import ( // strategy implements behavior for ConfigMap objects type strategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating ConfigMap // objects via the REST API. -var Strategy = strategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = strategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // Strategy should implement rest.RESTCreateStrategy var _ rest.RESTCreateStrategy = Strategy diff --git a/pkg/registry/core/endpoint/strategy.go b/pkg/registry/core/endpoint/strategy.go index f67a0c34ba2..0238105d576 100644 --- a/pkg/registry/core/endpoint/strategy.go +++ b/pkg/registry/core/endpoint/strategy.go @@ -22,6 +22,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" utilvalidation "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" api "k8s.io/kubernetes/pkg/apis/core" @@ -31,13 +32,13 @@ import ( // endpointsStrategy implements behavior for Endpoints type endpointsStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Endpoint // objects via the REST API. -var Strategy = endpointsStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = endpointsStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped is true for endpoints. func (endpointsStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/core/event/strategy.go b/pkg/registry/core/event/strategy.go index 94f76598f11..294683a5bf9 100644 --- a/pkg/registry/core/event/strategy.go +++ b/pkg/registry/core/event/strategy.go @@ -36,13 +36,13 @@ import ( ) type eventStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating // Event objects via the REST API. -var Strategy = eventStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = eventStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (eventStrategy) DefaultGarbageCollectionPolicy(ctx context.Context) rest.GarbageCollectionPolicy { return rest.Unsupported diff --git a/pkg/registry/core/limitrange/strategy.go b/pkg/registry/core/limitrange/strategy.go index 479d958ca78..bc524d00959 100644 --- a/pkg/registry/core/limitrange/strategy.go +++ b/pkg/registry/core/limitrange/strategy.go @@ -22,6 +22,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/uuid" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" api "k8s.io/kubernetes/pkg/apis/core" @@ -29,13 +30,13 @@ import ( ) type limitrangeStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating // LimitRange objects via the REST API. -var Strategy = limitrangeStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = limitrangeStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (limitrangeStrategy) NamespaceScoped() bool { return true diff --git a/pkg/registry/core/namespace/strategy.go b/pkg/registry/core/namespace/strategy.go index 9c5a7347ac7..66b8adba9ac 100644 --- a/pkg/registry/core/namespace/strategy.go +++ b/pkg/registry/core/namespace/strategy.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/registry/rest" apistorage "k8s.io/apiserver/pkg/storage" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -36,13 +37,13 @@ import ( // namespaceStrategy implements behavior for Namespaces type namespaceStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Namespace // objects via the REST API. -var Strategy = namespaceStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = namespaceStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped is false for namespaces. func (namespaceStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/core/node/strategy.go b/pkg/registry/core/node/strategy.go index 7588971d4d2..fda452fa1da 100644 --- a/pkg/registry/core/node/strategy.go +++ b/pkg/registry/core/node/strategy.go @@ -33,6 +33,7 @@ import ( utilvalidation "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/registry/rest" pkgstorage "k8s.io/apiserver/pkg/storage" "k8s.io/apiserver/pkg/storage/names" utilfeature "k8s.io/apiserver/pkg/util/feature" @@ -46,13 +47,13 @@ import ( // nodeStrategy implements behavior for nodes type nodeStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Nodes is the default logic that applies when creating and updating Node // objects. -var Strategy = nodeStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = nodeStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped is false for nodes. func (nodeStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/core/persistentvolume/strategy.go b/pkg/registry/core/persistentvolume/strategy.go index 395d84afc7e..a15755369c7 100644 --- a/pkg/registry/core/persistentvolume/strategy.go +++ b/pkg/registry/core/persistentvolume/strategy.go @@ -26,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -38,13 +39,13 @@ import ( // persistentvolumeStrategy implements behavior for PersistentVolume objects type persistentvolumeStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating PersistentVolume // objects via the REST API. -var Strategy = persistentvolumeStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = persistentvolumeStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (persistentvolumeStrategy) NamespaceScoped() bool { return false diff --git a/pkg/registry/core/persistentvolumeclaim/strategy.go b/pkg/registry/core/persistentvolumeclaim/strategy.go index a35cee7d9a8..51ceb736253 100644 --- a/pkg/registry/core/persistentvolumeclaim/strategy.go +++ b/pkg/registry/core/persistentvolumeclaim/strategy.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage" "k8s.io/apiserver/pkg/storage/names" "sigs.k8s.io/structured-merge-diff/v6/fieldpath" @@ -37,13 +38,13 @@ import ( // persistentvolumeclaimStrategy implements behavior for PersistentVolumeClaim objects type persistentvolumeclaimStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating PersistentVolumeClaim // objects via the REST API. -var Strategy = persistentvolumeclaimStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = persistentvolumeclaimStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (persistentvolumeclaimStrategy) NamespaceScoped() bool { return true diff --git a/pkg/registry/core/pod/strategy.go b/pkg/registry/core/pod/strategy.go index 250c4bf101d..08ebe4bf953 100644 --- a/pkg/registry/core/pod/strategy.go +++ b/pkg/registry/core/pod/strategy.go @@ -42,6 +42,7 @@ import ( "k8s.io/apimachinery/pkg/util/validation/field" apiserverfeatures "k8s.io/apiserver/pkg/features" "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage" "k8s.io/apiserver/pkg/storage/names" utilfeature "k8s.io/apiserver/pkg/util/feature" @@ -58,13 +59,13 @@ import ( // podStrategy implements behavior for Pods type podStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Pod // objects via the REST API. -var Strategy = podStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = podStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped is true for pods. func (podStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/core/podtemplate/strategy.go b/pkg/registry/core/podtemplate/strategy.go index 24cdb6438a9..6f7e59ddb68 100644 --- a/pkg/registry/core/podtemplate/strategy.go +++ b/pkg/registry/core/podtemplate/strategy.go @@ -22,6 +22,7 @@ import ( apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/api/pod" @@ -31,13 +32,13 @@ import ( // podTemplateStrategy implements behavior for PodTemplates type podTemplateStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating PodTemplate // objects via the REST API. -var Strategy = podTemplateStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = podTemplateStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped is true for pod templates. func (podTemplateStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/core/replicationcontroller/declarative_validation_test.go b/pkg/registry/core/replicationcontroller/declarative_validation_test.go index 050a3c2435c..8cb595700d1 100644 --- a/pkg/registry/core/replicationcontroller/declarative_validation_test.go +++ b/pkg/registry/core/replicationcontroller/declarative_validation_test.go @@ -189,7 +189,7 @@ func TestDeclarativeValidateForDeclarative(t *testing.T) { } for k, tc := range testCases { t.Run(k, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs) }) } } @@ -274,7 +274,7 @@ func TestValidateUpdateForDeclarative(t *testing.T) { t.Run(k, func(t *testing.T) { tc.old.ObjectMeta.ResourceVersion = "1" tc.update.ObjectMeta.ResourceVersion = "1" - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, Strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, Strategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/core/replicationcontroller/storage/storage.go b/pkg/registry/core/replicationcontroller/storage/storage.go index bee5ffb8c28..d8c3ed15573 100644 --- a/pkg/registry/core/replicationcontroller/storage/storage.go +++ b/pkg/registry/core/replicationcontroller/storage/storage.go @@ -314,7 +314,8 @@ func (i *scaleUpdatedObjectInfo) UpdatedObject(ctx context.Context, oldObj runti } errs := validation.ValidateScale(scale) - errs = rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, scale, oldScale, errs, operation.Update, rest.WithSubresourceMapper(i.scaleGVKMapper)) + dv := rest.DeclarativeValidation{Scheme: legacyscheme.Scheme} + errs = dv.ValidateDeclaratively(ctx, scale, oldScale, errs, operation.Update, rest.DeclarativeValidationConfig{SubresourceGVKMapper: i.scaleGVKMapper}) if len(errs) > 0 { return nil, errors.NewInvalid(autoscaling.Kind("Scale"), replicationcontroller.Name, errs) diff --git a/pkg/registry/core/replicationcontroller/strategy.go b/pkg/registry/core/replicationcontroller/strategy.go index 9fed503ca63..44d99f3289f 100644 --- a/pkg/registry/core/replicationcontroller/strategy.go +++ b/pkg/registry/core/replicationcontroller/strategy.go @@ -28,7 +28,6 @@ import ( corev1 "k8s.io/api/core/v1" apiequality "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -49,12 +48,12 @@ import ( // rcStrategy implements verification logic for Replication Controllers. type rcStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Replication Controller objects. -var Strategy = rcStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = rcStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // DefaultGarbageCollectionPolicy returns OrphanDependents for v1 for backwards compatibility, // and DeleteDependents for all other versions. @@ -127,8 +126,7 @@ func (rcStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorL opts := pod.GetValidationOptionsFromPodTemplate(controller.Spec.Template, nil) // Run imperative validation - allErrs := corevalidation.ValidateReplicationController(controller, opts) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, controller, nil, allErrs, operation.Create) + return corevalidation.ValidateReplicationController(controller, opts) } // WarningsOnCreate returns warnings for the creation of the given object. @@ -177,7 +175,7 @@ func (rcStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) f } } - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newRc, oldRc, errs, operation.Update) + return errs } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/core/resourcequota/strategy.go b/pkg/registry/core/resourcequota/strategy.go index 5a6dda4820f..f96c8149dbc 100644 --- a/pkg/registry/core/resourcequota/strategy.go +++ b/pkg/registry/core/resourcequota/strategy.go @@ -22,6 +22,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" api "k8s.io/kubernetes/pkg/apis/core" @@ -31,13 +32,13 @@ import ( // resourcequotaStrategy implements behavior for ResourceQuota objects type resourcequotaStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating ResourceQuota // objects via the REST API. -var Strategy = resourcequotaStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = resourcequotaStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped is true for resourcequotas. func (resourcequotaStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/core/secret/strategy.go b/pkg/registry/core/secret/strategy.go index 18b6c0116d7..1e20e8c0d78 100644 --- a/pkg/registry/core/secret/strategy.go +++ b/pkg/registry/core/secret/strategy.go @@ -36,13 +36,13 @@ import ( // strategy implements behavior for Secret objects type strategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Secret // objects via the REST API. -var Strategy = strategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = strategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} var _ = rest.RESTCreateStrategy(Strategy) diff --git a/pkg/registry/core/service/strategy.go b/pkg/registry/core/service/strategy.go index e41a10bb045..e0eece92120 100644 --- a/pkg/registry/core/service/strategy.go +++ b/pkg/registry/core/service/strategy.go @@ -28,6 +28,7 @@ import ( utilvalidation "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/registry/rest" pkgstorage "k8s.io/apiserver/pkg/storage" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -40,13 +41,13 @@ import ( // svcStrategy implements behavior for Services type svcStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Services // objects via the REST API. -var Strategy = svcStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = svcStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped is true for services. func (svcStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/core/serviceaccount/strategy.go b/pkg/registry/core/serviceaccount/strategy.go index 5f28ae74994..631a3859c21 100644 --- a/pkg/registry/core/serviceaccount/strategy.go +++ b/pkg/registry/core/serviceaccount/strategy.go @@ -22,6 +22,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" api "k8s.io/kubernetes/pkg/apis/core" @@ -31,13 +32,13 @@ import ( // strategy implements behavior for ServiceAccount objects type strategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating ServiceAccount // objects via the REST API. -var Strategy = strategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = strategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (strategy) NamespaceScoped() bool { return true diff --git a/pkg/registry/discovery/endpointslice/declarative_validation_test.go b/pkg/registry/discovery/endpointslice/declarative_validation_test.go index e4c7f54c41a..fed70ca41f3 100644 --- a/pkg/registry/discovery/endpointslice/declarative_validation_test.go +++ b/pkg/registry/discovery/endpointslice/declarative_validation_test.go @@ -85,7 +85,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) { } for name, tc := range testCases { t.Run(name, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs) }) } } @@ -149,7 +149,7 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) { }) tc.oldObj.ResourceVersion = "1" tc.updateObj.ResourceVersion = "2" - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, Strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, Strategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/discovery/endpointslice/strategy.go b/pkg/registry/discovery/endpointslice/strategy.go index 09269868411..a033ecda862 100644 --- a/pkg/registry/discovery/endpointslice/strategy.go +++ b/pkg/registry/discovery/endpointslice/strategy.go @@ -24,7 +24,6 @@ import ( discoveryv1 "k8s.io/api/discovery/v1" discoveryv1beta1 "k8s.io/api/discovery/v1beta1" apiequality "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/operation" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" @@ -46,12 +45,12 @@ import ( // endpointSliceStrategy implements verification logic for Replication. type endpointSliceStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Replication EndpointSlice objects. -var Strategy = endpointSliceStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = endpointSliceStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped returns true because all EndpointSlices need to be within a namespace. func (endpointSliceStrategy) NamespaceScoped() bool { @@ -93,8 +92,7 @@ func (endpointSliceStrategy) PrepareForUpdate(ctx context.Context, obj, old runt // Validate validates a new EndpointSlice. func (endpointSliceStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { endpointSlice := obj.(*discovery.EndpointSlice) - allErrs := validation.ValidateEndpointSliceCreate(endpointSlice) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, endpointSlice, nil, allErrs, operation.Create) + return validation.ValidateEndpointSliceCreate(endpointSlice) } // WarningsOnCreate returns warnings for the creation of the given object. @@ -122,8 +120,7 @@ func (endpointSliceStrategy) AllowCreateOnUpdate() bool { func (endpointSliceStrategy) ValidateUpdate(ctx context.Context, new, old runtime.Object) field.ErrorList { newEPS := new.(*discovery.EndpointSlice) oldEPS := old.(*discovery.EndpointSlice) - allErrs := validation.ValidateEndpointSliceUpdate(newEPS, oldEPS) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newEPS, oldEPS, allErrs, operation.Update) + return validation.ValidateEndpointSliceUpdate(newEPS, oldEPS) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/flowcontrol/flowschema/strategy.go b/pkg/registry/flowcontrol/flowschema/strategy.go index eec08ab5de5..99a3e0c879d 100644 --- a/pkg/registry/flowcontrol/flowschema/strategy.go +++ b/pkg/registry/flowcontrol/flowschema/strategy.go @@ -22,6 +22,7 @@ import ( apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/flowcontrol" @@ -31,12 +32,12 @@ import ( // flowSchemaStrategy implements verification logic for FlowSchema. type flowSchemaStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating flow schema objects. -var Strategy = flowSchemaStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = flowSchemaStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped returns false because all PriorityClasses are global. func (flowSchemaStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/flowcontrol/prioritylevelconfiguration/declarative_validation_test.go b/pkg/registry/flowcontrol/prioritylevelconfiguration/declarative_validation_test.go index 4a36e699811..d3af47834c2 100644 --- a/pkg/registry/flowcontrol/prioritylevelconfiguration/declarative_validation_test.go +++ b/pkg/registry/flowcontrol/prioritylevelconfiguration/declarative_validation_test.go @@ -107,7 +107,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs) }) } } @@ -183,7 +183,7 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) { IsResourceRequest: true, Verb: "update", }) - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, Strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, Strategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/flowcontrol/prioritylevelconfiguration/strategy.go b/pkg/registry/flowcontrol/prioritylevelconfiguration/strategy.go index 0c1ec288255..b400b8cf71d 100644 --- a/pkg/registry/flowcontrol/prioritylevelconfiguration/strategy.go +++ b/pkg/registry/flowcontrol/prioritylevelconfiguration/strategy.go @@ -20,7 +20,6 @@ import ( "context" apiequality "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/validation/field" @@ -35,12 +34,12 @@ import ( // priorityLevelConfigurationStrategy implements verification logic for priority level configurations. type priorityLevelConfigurationStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating priority level configuration objects. -var Strategy = priorityLevelConfigurationStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = priorityLevelConfigurationStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped returns false because all PriorityClasses are global. func (priorityLevelConfigurationStrategy) NamespaceScoped() bool { @@ -98,8 +97,7 @@ func (priorityLevelConfigurationStrategy) Validate(ctx context.Context, obj runt // all servers are at 1.29+ and will honor the zero value correctly. plc := obj.(*flowcontrol.PriorityLevelConfiguration) opts := validation.PriorityLevelValidationOptions{} - allErrs := validation.ValidatePriorityLevelConfiguration(plc, getRequestGroupVersion(ctx), opts) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, plc, nil, allErrs, operation.Create) + return validation.ValidatePriorityLevelConfiguration(plc, getRequestGroupVersion(ctx), opts) } // WarningsOnCreate returns warnings for the creation of the given object. @@ -123,7 +121,7 @@ func (priorityLevelConfigurationStrategy) AllowCreateOnUpdate() bool { // ValidateUpdate is the default update validation for an end user. func (priorityLevelConfigurationStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { newPL := obj.(*flowcontrol.PriorityLevelConfiguration) - oldPL := old.(*flowcontrol.PriorityLevelConfiguration) + _ = old.(*flowcontrol.PriorityLevelConfiguration) // 1.28 server is not aware of the roundtrip annotation, and will // default any 0 value persisted (for the NominalConcurrencyShares @@ -133,8 +131,7 @@ func (priorityLevelConfigurationStrategy) ValidateUpdate(ctx context.Context, ob // via v1 or v1beta3(with the roundtrip annotation) until we know // all servers are at 1.29+ and will honor the zero value correctly. opts := validation.PriorityLevelValidationOptions{} - allErrs := validation.ValidatePriorityLevelConfiguration(newPL, getRequestGroupVersion(ctx), opts) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newPL, oldPL, allErrs, operation.Update) + return validation.ValidatePriorityLevelConfiguration(newPL, getRequestGroupVersion(ctx), opts) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/networking/ingress/strategy.go b/pkg/registry/networking/ingress/strategy.go index b6c7bbcf754..14d56294895 100644 --- a/pkg/registry/networking/ingress/strategy.go +++ b/pkg/registry/networking/ingress/strategy.go @@ -24,6 +24,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" utilvalidation "k8s.io/apimachinery/pkg/util/validation" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/networking" @@ -37,12 +38,12 @@ const ( // ingressStrategy implements verification logic for Replication Ingress. type ingressStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Replication Ingress objects. -var Strategy = ingressStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = ingressStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped returns true because all Ingress' need to be within a namespace. func (ingressStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/networking/ingressclass/declarative_validation_test.go b/pkg/registry/networking/ingressclass/declarative_validation_test.go index d622c0ebd0b..ab75498e826 100644 --- a/pkg/registry/networking/ingressclass/declarative_validation_test.go +++ b/pkg/registry/networking/ingressclass/declarative_validation_test.go @@ -76,7 +76,7 @@ func TestDeclarativeValidateParameter(t *testing.T) { t, ctx, &tc.input, - Strategy.Validate, + Strategy, tc.expectedErrs, ) }) @@ -155,7 +155,7 @@ func TestDeclarativeValidateUpdateParameters(t *testing.T) { ctx, &tc.updateObj, &tc.oldObj, - Strategy.ValidateUpdate, + Strategy, tc.expectedErrs, ) }) diff --git a/pkg/registry/networking/ingressclass/strategy.go b/pkg/registry/networking/ingressclass/strategy.go index 15ca00da8e0..0c16014f8eb 100644 --- a/pkg/registry/networking/ingressclass/strategy.go +++ b/pkg/registry/networking/ingressclass/strategy.go @@ -18,7 +18,7 @@ package ingressclass import ( "context" - "k8s.io/apimachinery/pkg/api/operation" + "k8s.io/apiserver/pkg/registry/rest" apiequality "k8s.io/apimachinery/pkg/api/equality" @@ -33,13 +33,13 @@ import ( // ingressClassStrategy implements verification logic for IngressClass // resources. type ingressClassStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating // IngressClass objects. -var Strategy = ingressClassStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = ingressClassStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped returns false because IngressClass is a non-namespaced // resource. @@ -69,8 +69,7 @@ func (ingressClassStrategy) PrepareForUpdate(ctx context.Context, obj, old runti // Validate validates a new IngressClass. func (ingressClassStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { ingressClass := obj.(*networking.IngressClass) - allErrs := validation.ValidateIngressClass(ingressClass) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, ingressClass, nil, allErrs, operation.Create) + return validation.ValidateIngressClass(ingressClass) } // WarningsOnCreate returns warnings for the creation of the given object. @@ -93,8 +92,7 @@ func (ingressClassStrategy) ValidateUpdate(ctx context.Context, obj, old runtime newIngressClass := obj.(*networking.IngressClass) oldIngressClass := old.(*networking.IngressClass) - allErrs := validation.ValidateIngressClassUpdate(newIngressClass, oldIngressClass) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newIngressClass, oldIngressClass, allErrs, operation.Update) + return validation.ValidateIngressClassUpdate(newIngressClass, oldIngressClass) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/networking/ipaddress/declarative_validation_test.go b/pkg/registry/networking/ipaddress/declarative_validation_test.go index d1af4953252..f92bf9b99ff 100644 --- a/pkg/registry/networking/ipaddress/declarative_validation_test.go +++ b/pkg/registry/networking/ipaddress/declarative_validation_test.go @@ -74,7 +74,7 @@ func TestDeclarativeValidateIPAddress(t *testing.T) { t, ctx, &tc.input, - Strategy.Validate, + Strategy, tc.expectedErrs, ) }) @@ -168,7 +168,7 @@ func TestDeclarativeValidateIPAddressUpdate(t *testing.T) { ctx, &tc.updateObj, &tc.oldObj, - Strategy.ValidateUpdate, + Strategy, tc.expectedErrs, ) }) diff --git a/pkg/registry/networking/ipaddress/strategy.go b/pkg/registry/networking/ipaddress/strategy.go index 9afbf501848..f5130a0e6d9 100644 --- a/pkg/registry/networking/ipaddress/strategy.go +++ b/pkg/registry/networking/ipaddress/strategy.go @@ -19,7 +19,6 @@ package ipaddress import ( "context" - "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/rest" @@ -31,7 +30,7 @@ import ( // ipAddressStrategy implements verification logic for Replication. type ipAddressStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } @@ -43,7 +42,7 @@ func (noopNameGenerator) GenerateName(base string) string { } // Strategy is the default logic that applies when creating and updating Replication IPAddress objects. -var Strategy = ipAddressStrategy{legacyscheme.Scheme, noopNameGenerator{}} +var Strategy = ipAddressStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, noopNameGenerator{}} // Strategy should implement rest.RESTCreateStrategy var _ rest.RESTCreateStrategy = Strategy @@ -73,8 +72,7 @@ func (ipAddressStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime. // Validate validates a new IPAddress. func (ipAddressStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { ipAddress := obj.(*networking.IPAddress) - err := validation.ValidateIPAddress(ipAddress) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, ipAddress, nil, err, operation.Create) + return validation.ValidateIPAddress(ipAddress) } // Canonicalize normalizes the object after validation. @@ -92,7 +90,7 @@ func (ipAddressStrategy) ValidateUpdate(ctx context.Context, new, old runtime.Ob oldIPAddress := old.(*networking.IPAddress) errList := validation.ValidateIPAddress(newIPAddress) errList = append(errList, validation.ValidateIPAddressUpdate(newIPAddress, oldIPAddress)...) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newIPAddress, oldIPAddress, errList, operation.Update) + return errList } // AllowUnconditionalUpdate is the default update policy for IPAddress objects. diff --git a/pkg/registry/networking/networkpolicy/declarative_validation_test.go b/pkg/registry/networking/networkpolicy/declarative_validation_test.go index 49d6dd57684..e4372d1e162 100644 --- a/pkg/registry/networking/networkpolicy/declarative_validation_test.go +++ b/pkg/registry/networking/networkpolicy/declarative_validation_test.go @@ -79,7 +79,7 @@ func TestDeclarativeValidateIPBlockCIDR(t *testing.T) { t, ctx, &tc.input, - Strategy.Validate, + Strategy, tc.expectedErrs, ) }) @@ -147,7 +147,7 @@ func TestDeclarativeValidateIPBlockCIDRUpdate(t *testing.T) { ctx, &tc.updateObj, &tc.oldObj, - Strategy.ValidateUpdate, + Strategy, tc.expectedErrs, ) }) diff --git a/pkg/registry/networking/networkpolicy/strategy.go b/pkg/registry/networking/networkpolicy/strategy.go index d2fb8c5902e..b2f4365ddfe 100644 --- a/pkg/registry/networking/networkpolicy/strategy.go +++ b/pkg/registry/networking/networkpolicy/strategy.go @@ -18,7 +18,6 @@ package networkpolicy import ( "context" - "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apiserver/pkg/registry/rest" "reflect" @@ -33,12 +32,12 @@ import ( // networkPolicyStrategy implements verification logic for NetworkPolicies type networkPolicyStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating NetworkPolicy objects. -var Strategy = networkPolicyStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = networkPolicyStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped returns true because all NetworkPolicies need to be within a namespace. func (networkPolicyStrategy) NamespaceScoped() bool { @@ -68,9 +67,7 @@ func (networkPolicyStrategy) PrepareForUpdate(ctx context.Context, obj, old runt func (networkPolicyStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { networkPolicy := obj.(*networking.NetworkPolicy) ops := validation.ValidationOptionsForNetworking(networkPolicy, nil) - allErrs := validation.ValidateNetworkPolicy(networkPolicy, ops) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, networkPolicy, nil, allErrs, operation.Create) - + return validation.ValidateNetworkPolicy(networkPolicy, ops) } // WarningsOnCreate returns warnings for the creation of the given object. @@ -89,8 +86,7 @@ func (networkPolicyStrategy) AllowCreateOnUpdate() bool { // ValidateUpdate is the default update validation for an end user. func (networkPolicyStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { opts := validation.ValidationOptionsForNetworking(obj.(*networking.NetworkPolicy), old.(*networking.NetworkPolicy)) - allErrs := validation.ValidateNetworkPolicyUpdate(obj.(*networking.NetworkPolicy), old.(*networking.NetworkPolicy), opts) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, old, allErrs, operation.Update) + return validation.ValidateNetworkPolicyUpdate(obj.(*networking.NetworkPolicy), old.(*networking.NetworkPolicy), opts) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/networking/servicecidr/strategy.go b/pkg/registry/networking/servicecidr/strategy.go index c48e00007a9..e70ea4fd285 100644 --- a/pkg/registry/networking/servicecidr/strategy.go +++ b/pkg/registry/networking/servicecidr/strategy.go @@ -35,12 +35,12 @@ import ( // serviceCIDRStrategy implements verification logic for ServiceCIDR allocators. type serviceCIDRStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Replication ServiceCIDR objects. -var Strategy = serviceCIDRStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = serviceCIDRStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // Strategy should implement rest.RESTCreateStrategy var _ rest.RESTCreateStrategy = Strategy diff --git a/pkg/registry/node/runtimeclass/declarative_validation_test.go b/pkg/registry/node/runtimeclass/declarative_validation_test.go index b0633f6279a..011246db2b0 100644 --- a/pkg/registry/node/runtimeclass/declarative_validation_test.go +++ b/pkg/registry/node/runtimeclass/declarative_validation_test.go @@ -102,7 +102,7 @@ func TestRuntimeClass_DeclarativeValidate_Create(t *testing.T) { for name, tc := range tests { t.Run(name, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.obj, Strategy.Validate, tc.expectedErrs, + apitesting.VerifyValidationEquivalence(t, ctx, &tc.obj, Strategy, tc.expectedErrs, apitesting.WithNormalizationRules(validation.NodeNormalizationRules...)) }) } @@ -148,7 +148,7 @@ func TestRuntimeClass_DeclarativeValidate_Update(t *testing.T) { t.Run(name, func(t *testing.T) { tc.oldObj.ObjectMeta.ResourceVersion = "1" tc.newObj.ObjectMeta.ResourceVersion = "1" - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.newObj, &tc.oldObj, Strategy.ValidateUpdate, tc.expectedErrs, apitesting.WithNormalizationRules(validation.NodeNormalizationRules...)) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.newObj, &tc.oldObj, Strategy, tc.expectedErrs, apitesting.WithNormalizationRules(validation.NodeNormalizationRules...)) }) } }) diff --git a/pkg/registry/node/runtimeclass/strategy.go b/pkg/registry/node/runtimeclass/strategy.go index bbfece5cdd0..7e2f43c6b43 100644 --- a/pkg/registry/node/runtimeclass/strategy.go +++ b/pkg/registry/node/runtimeclass/strategy.go @@ -18,7 +18,6 @@ package runtimeclass import ( "context" - "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" @@ -32,12 +31,12 @@ import ( // strategy implements verification logic for RuntimeClass. type strategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating RuntimeClass objects. -var Strategy = strategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = strategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // Strategy should implement rest.RESTCreateStrategy var _ rest.RESTCreateStrategy = Strategy @@ -71,9 +70,13 @@ func (strategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { // Validate validates a new RuntimeClass. Validation must check for a correct signature. func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { runtimeClass := obj.(*node.RuntimeClass) - allErrs := validation.ValidateRuntimeClass(runtimeClass) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, runtimeClass, nil, allErrs, operation.Create, rest.WithNormalizationRules(validation.NodeNormalizationRules)) + return validation.ValidateRuntimeClass(runtimeClass) +} +// DeclarativeValidationConfig implements rest.DeclarativeValidationConfigurer to supply declarative +// validation options to the generic BeforeCreate/BeforeUpdate code path. +func (strategy) DeclarativeValidationConfig(ctx context.Context, obj, oldObj runtime.Object) rest.DeclarativeValidationConfig { + return rest.DeclarativeValidationConfig{NormalizationRules: validation.NodeNormalizationRules} } // WarningsOnCreate returns warnings for the creation of the given object. @@ -91,8 +94,7 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie newObj := obj.(*node.RuntimeClass) errorList := validation.ValidateRuntimeClass(newObj) errorList = append(errorList, validation.ValidateRuntimeClassUpdate(newObj, old.(*node.RuntimeClass))...) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newObj, old, errorList, operation.Update, rest.WithNormalizationRules(validation.NodeNormalizationRules)) - + return errorList } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/policy/poddisruptionbudget/strategy.go b/pkg/registry/policy/poddisruptionbudget/strategy.go index cce2a99e5b5..6e43755f99b 100644 --- a/pkg/registry/policy/poddisruptionbudget/strategy.go +++ b/pkg/registry/policy/poddisruptionbudget/strategy.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/validation/field" genericapirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/policy" @@ -34,12 +35,12 @@ import ( // podDisruptionBudgetStrategy implements verification logic for PodDisruptionBudgets. type podDisruptionBudgetStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating PodDisruptionBudget objects. -var Strategy = podDisruptionBudgetStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = podDisruptionBudgetStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped returns true because all PodDisruptionBudget' need to be within a namespace. func (podDisruptionBudgetStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/rbac/clusterrole/declarative_validation_test.go b/pkg/registry/rbac/clusterrole/declarative_validation_test.go index f401bdcc600..d66b60e621b 100644 --- a/pkg/registry/rbac/clusterrole/declarative_validation_test.go +++ b/pkg/registry/rbac/clusterrole/declarative_validation_test.go @@ -62,7 +62,7 @@ func testDeclarativeValidateForDeclarative(t *testing.T, apiVersion string) { } for k, tc := range testCases { t.Run(k, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs) }) } } @@ -100,7 +100,7 @@ func testValidateUpdateForDeclarative(t *testing.T, apiVersion string) { t.Run(k, func(t *testing.T) { tc.old.ResourceVersion = "1" tc.update.ResourceVersion = "2" - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, Strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, Strategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/rbac/clusterrole/strategy.go b/pkg/registry/rbac/clusterrole/strategy.go index 13062cfdda4..2dd771cacdc 100644 --- a/pkg/registry/rbac/clusterrole/strategy.go +++ b/pkg/registry/rbac/clusterrole/strategy.go @@ -19,7 +19,6 @@ package clusterrole import ( "context" - "k8s.io/apimachinery/pkg/api/operation" metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" @@ -32,13 +31,13 @@ import ( // strategy implements behavior for ClusterRoles type strategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating // ClusterRole objects. -var Strategy = strategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = strategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // Strategy should implement rest.RESTCreateStrategy var _ rest.RESTCreateStrategy = Strategy @@ -76,9 +75,7 @@ func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorLis opts := validation.ClusterRoleValidationOptions{ AllowInvalidLabelValueInSelector: false, } - allErrs := validation.ValidateClusterRole(clusterRole, opts) - - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, clusterRole, nil, allErrs, operation.Create) + return validation.ValidateClusterRole(clusterRole, opts) } // WarningsOnCreate returns warnings for the creation of the given object. @@ -96,9 +93,7 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie opts := validation.ClusterRoleValidationOptions{ AllowInvalidLabelValueInSelector: hasInvalidLabelValueInLabelSelector(oldObj), } - errs := validation.ValidateClusterRoleUpdate(newObj, oldObj, opts) - - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newObj, oldObj, errs, operation.Update) + return validation.ValidateClusterRoleUpdate(newObj, oldObj, opts) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/rbac/clusterrolebinding/strategy.go b/pkg/registry/rbac/clusterrolebinding/strategy.go index 7bfd68c17e1..cd1fff38833 100644 --- a/pkg/registry/rbac/clusterrolebinding/strategy.go +++ b/pkg/registry/rbac/clusterrolebinding/strategy.go @@ -30,13 +30,13 @@ import ( // strategy implements behavior for ClusterRoleBindings type strategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // strategy is the default logic that applies when creating and updating // ClusterRoleBinding objects. -var Strategy = strategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = strategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // Strategy should implement rest.RESTCreateStrategy var _ rest.RESTCreateStrategy = Strategy diff --git a/pkg/registry/rbac/role/declarative_validation_test.go b/pkg/registry/rbac/role/declarative_validation_test.go index 73ce636f127..c65a1e9ba03 100644 --- a/pkg/registry/rbac/role/declarative_validation_test.go +++ b/pkg/registry/rbac/role/declarative_validation_test.go @@ -69,7 +69,7 @@ func testDeclarativeValidateForDeclarative(t *testing.T, apiVersion string) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs) }) } } @@ -113,7 +113,7 @@ func testValidateUpdateForDeclarative(t *testing.T, apiVersion string) { t.Run(name, func(t *testing.T) { tc.old.ResourceVersion = "1" tc.update.ResourceVersion = "2" - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, Strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, Strategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/rbac/role/strategy.go b/pkg/registry/rbac/role/strategy.go index b8098fad6b0..125e6179d1c 100644 --- a/pkg/registry/rbac/role/strategy.go +++ b/pkg/registry/rbac/role/strategy.go @@ -19,7 +19,6 @@ package role import ( "context" - "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/rest" @@ -31,13 +30,13 @@ import ( // strategy implements behavior for Roles type strategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating // Role objects. -var Strategy = strategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = strategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // Strategy should implement rest.RESTCreateStrategy var _ rest.RESTCreateStrategy = Strategy @@ -72,8 +71,7 @@ func (strategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { // Validate validates a new Role. Validation must check for a correct signature. func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { role := obj.(*rbac.Role) - allErrs := validation.ValidateRole(role) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, role, nil, allErrs, operation.Create) + return validation.ValidateRole(role) } // WarningsOnCreate returns warnings for the creation of the given object. @@ -88,8 +86,7 @@ func (strategy) Canonicalize(obj runtime.Object) { func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { newObj := obj.(*rbac.Role) oldObj := old.(*rbac.Role) - errs := validation.ValidateRoleUpdate(newObj, oldObj) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newObj, oldObj, errs, operation.Update) + return validation.ValidateRoleUpdate(newObj, oldObj) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/rbac/rolebinding/declarative_validation_test.go b/pkg/registry/rbac/rolebinding/declarative_validation_test.go index 5dba716828c..56e09e8e2fd 100644 --- a/pkg/registry/rbac/rolebinding/declarative_validation_test.go +++ b/pkg/registry/rbac/rolebinding/declarative_validation_test.go @@ -99,7 +99,7 @@ func testDeclarativeValidateForDeclarative(t *testing.T, apiVersion string) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/rbac/rolebinding/strategy.go b/pkg/registry/rbac/rolebinding/strategy.go index a2fba905169..94405c06fcc 100644 --- a/pkg/registry/rbac/rolebinding/strategy.go +++ b/pkg/registry/rbac/rolebinding/strategy.go @@ -19,7 +19,6 @@ package rolebinding import ( "context" - "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/rest" @@ -31,13 +30,13 @@ import ( // strategy implements behavior for RoleBindings type strategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // strategy is the default logic that applies when creating and updating // RoleBinding objects. -var Strategy = strategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = strategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // Strategy should implement rest.RESTCreateStrategy var _ rest.RESTCreateStrategy = Strategy @@ -72,8 +71,7 @@ func (strategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { // Validate validates a new RoleBinding. Validation must check for a correct signature. func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { roleBinding := obj.(*rbac.RoleBinding) - allErrs := validation.ValidateRoleBinding(roleBinding) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, roleBinding, nil, allErrs, operation.Create) + return validation.ValidateRoleBinding(roleBinding) } // WarningsOnCreate returns warnings for the creation of the given object. @@ -90,9 +88,7 @@ func (strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) fie newRoleBinding := obj.(*rbac.RoleBinding) oldRoleBinding := old.(*rbac.RoleBinding) - allErrs := validation.ValidateRoleBindingUpdate(newRoleBinding, oldRoleBinding) - - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newRoleBinding, oldRoleBinding, allErrs, operation.Update) + return validation.ValidateRoleBindingUpdate(newRoleBinding, oldRoleBinding) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/resource/deviceclass/declarative_validation_test.go b/pkg/registry/resource/deviceclass/declarative_validation_test.go index f4bb221a4ec..7ec27609283 100644 --- a/pkg/registry/resource/deviceclass/declarative_validation_test.go +++ b/pkg/registry/resource/deviceclass/declarative_validation_test.go @@ -142,7 +142,7 @@ func TestDeclarativeValidate(t *testing.T) { for k, tc := range testCases { t.Run(k, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, strategy, tc.expectedErrs) }) } }) @@ -247,7 +247,7 @@ func TestDeclarativeValidateUpdate(t *testing.T) { t.Run(k, func(t *testing.T) { tc.old.ResourceVersion = "1" tc.update.ResourceVersion = "1" - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, strategy, tc.expectedErrs) }) } }) diff --git a/pkg/registry/resource/deviceclass/strategy.go b/pkg/registry/resource/deviceclass/strategy.go index 5815dfae0c1..312ef1e244d 100644 --- a/pkg/registry/resource/deviceclass/strategy.go +++ b/pkg/registry/resource/deviceclass/strategy.go @@ -20,7 +20,6 @@ import ( "context" apiequality "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/rest" @@ -34,11 +33,11 @@ import ( // deviceClassStrategy implements behavior for DeviceClass objects type deviceClassStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } -var Strategy = deviceClassStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = deviceClassStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (deviceClassStrategy) NamespaceScoped() bool { return false @@ -52,9 +51,7 @@ func (deviceClassStrategy) PrepareForCreate(ctx context.Context, obj runtime.Obj func (deviceClassStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { deviceClass := obj.(*resource.DeviceClass) - errorList := validation.ValidateDeviceClass(deviceClass) - - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, deviceClass, nil, errorList, operation.Create) + return validation.ValidateDeviceClass(deviceClass) } func (deviceClassStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { @@ -83,8 +80,7 @@ func (deviceClassStrategy) PrepareForUpdate(ctx context.Context, obj, old runtim func (deviceClassStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { newClass := obj.(*resource.DeviceClass) oldClass := old.(*resource.DeviceClass) - errorList := validation.ValidateDeviceClassUpdate(newClass, oldClass) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newClass, oldClass, errorList, operation.Update) + return validation.ValidateDeviceClassUpdate(newClass, oldClass) } func (deviceClassStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { diff --git a/pkg/registry/resource/devicetaintrule/strategy.go b/pkg/registry/resource/devicetaintrule/strategy.go index 5be8912bd5b..9e28dedc692 100644 --- a/pkg/registry/resource/devicetaintrule/strategy.go +++ b/pkg/registry/resource/devicetaintrule/strategy.go @@ -24,6 +24,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/resource" @@ -33,12 +34,12 @@ import ( // deviceTaintRuleStrategy implements behavior for DeviceTaintRule objects type deviceTaintRuleStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } var ( - Strategy = &deviceTaintRuleStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} + Strategy = &deviceTaintRuleStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} StatusStrategy = &deviceTaintRuleStatusStrategy{deviceTaintRuleStrategy: Strategy} ) diff --git a/pkg/registry/resource/resourceclaim/declarative_validation_test.go b/pkg/registry/resource/resourceclaim/declarative_validation_test.go index eb90bad8993..2d32da896f2 100644 --- a/pkg/registry/resource/resourceclaim/declarative_validation_test.go +++ b/pkg/registry/resource/resourceclaim/declarative_validation_test.go @@ -502,7 +502,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) { } for k, tc := range testCases { t.Run(k, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs, apitesting.WithNormalizationRules(validation.ResourceNormalizationRules...)) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs, apitesting.WithNormalizationRules(validation.ResourceNormalizationRules...)) }) } } @@ -820,7 +820,7 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) { t.Run(k, func(t *testing.T) { tc.old.ResourceVersion = "1" tc.update.ResourceVersion = "2" - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, Strategy.ValidateUpdate, tc.expectedErrs, apitesting.WithNormalizationRules(validation.ResourceNormalizationRules...)) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, Strategy, tc.expectedErrs, apitesting.WithNormalizationRules(validation.ResourceNormalizationRules...)) }) } } @@ -1437,7 +1437,7 @@ func testValidateStatusUpdateForDeclarative(t *testing.T, apiVersion string) { t.Run(k, func(t *testing.T) { tc.old.ObjectMeta.ResourceVersion = "1" tc.update.ObjectMeta.ResourceVersion = "1" - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, strategy.ValidateUpdate, tc.expectedErrs, apitesting.WithSubResources("status")) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, strategy, tc.expectedErrs, apitesting.WithSubResources("status")) }) } } diff --git a/pkg/registry/resource/resourceclaim/strategy.go b/pkg/registry/resource/resourceclaim/strategy.go index c72251f7f26..f2e3a7e1b5c 100644 --- a/pkg/registry/resource/resourceclaim/strategy.go +++ b/pkg/registry/resource/resourceclaim/strategy.go @@ -22,7 +22,6 @@ import ( "sigs.k8s.io/structured-merge-diff/v6/fieldpath" - "k8s.io/apimachinery/pkg/api/operation" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" @@ -49,7 +48,7 @@ import ( // resourceclaimStrategy implements behavior for ResourceClaim objects type resourceclaimStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator nsClient v1.NamespaceInterface authorizer authorizer.Authorizer @@ -58,7 +57,7 @@ type resourceclaimStrategy struct { // NewStrategy is the default logic that applies when creating and updating ResourceClaim objects. func NewStrategy(nsClient v1.NamespaceInterface, authorizer authorizer.Authorizer) *resourceclaimStrategy { return &resourceclaimStrategy{ - legacyscheme.Scheme, + rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator, nsClient, authorizer, @@ -104,7 +103,23 @@ func (s *resourceclaimStrategy) Validate(ctx context.Context, obj runtime.Object allErrs := resourceutils.AuthorizedForAdmin(ctx, claim.Spec.Devices.Requests, claim.Namespace, s.nsClient) allErrs = append(allErrs, validation.ValidateResourceClaim(claim)...) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, claim, nil, allErrs, operation.Create, rest.WithNormalizationRules(validation.ResourceNormalizationRules)) + return allErrs +} + +// DeclarativeValidationConfig implements rest.DeclarativeValidationConfigurer to supply declarative +// validation options to the generic BeforeCreate/BeforeUpdate code path. +// +// TODO: Behavior drift introduced when wiring declarative validation +// universally: the status substrategy embeds *resourceclaimStrategy and now +// inherits this method, so status updates pick up +// WithNormalizationRules(ResourceNormalizationRules). Previously the +// pre-migration inline declarative-validation call on the status subresource +// did NOT pass normalization rules. The change is additive (mismatch +// comparisons are stricter on status updates) but should be reviewed; if the +// status subresource should not use these rules, override +// ValidationConfig on resourceclaimStatusStrategy. +func (*resourceclaimStrategy) DeclarativeValidationConfig(ctx context.Context, obj, oldObj runtime.Object) rest.DeclarativeValidationConfig { + return rest.DeclarativeValidationConfig{NormalizationRules: validation.ResourceNormalizationRules} } func (*resourceclaimStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { @@ -130,8 +145,7 @@ func (s *resourceclaimStrategy) ValidateUpdate(ctx context.Context, obj, old run newClaim := obj.(*resource.ResourceClaim) oldClaim := old.(*resource.ResourceClaim) // AuthorizedForAdmin isn't needed here because the spec is immutable. - errorList := validation.ValidateResourceClaimUpdate(newClaim, oldClaim) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newClaim, oldClaim, errorList, operation.Update, rest.WithNormalizationRules(validation.ResourceNormalizationRules)) + return validation.ValidateResourceClaimUpdate(newClaim, oldClaim) } func (*resourceclaimStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { @@ -209,7 +223,7 @@ func (r *resourceclaimStatusStrategy) ValidateUpdate(ctx context.Context, obj, o } } errs = append(errs, validation.ValidateResourceClaimStatusUpdate(newClaim, oldClaim)...) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newClaim, oldClaim, errs, operation.Update) + return errs } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/resource/resourceclaimtemplate/strategy.go b/pkg/registry/resource/resourceclaimtemplate/strategy.go index f53e31ba753..eda8b97379a 100644 --- a/pkg/registry/resource/resourceclaimtemplate/strategy.go +++ b/pkg/registry/resource/resourceclaimtemplate/strategy.go @@ -25,6 +25,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" v1 "k8s.io/client-go/kubernetes/typed/core/v1" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -36,7 +37,7 @@ import ( // resourceClaimTemplateStrategy implements behavior for ResourceClaimTemplate objects type resourceClaimTemplateStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator nsClient v1.NamespaceInterface } @@ -44,7 +45,7 @@ type resourceClaimTemplateStrategy struct { // NewStrategy is the default logic that applies when creating and updating ResourceClaimTemplate objects. func NewStrategy(nsClient v1.NamespaceInterface) *resourceClaimTemplateStrategy { return &resourceClaimTemplateStrategy{ - legacyscheme.Scheme, + rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator, nsClient, } diff --git a/pkg/registry/resource/resourcepoolstatusrequest/declarative_validation_test.go b/pkg/registry/resource/resourcepoolstatusrequest/declarative_validation_test.go index 6085bc0c2a3..d196f37fe20 100644 --- a/pkg/registry/resource/resourcepoolstatusrequest/declarative_validation_test.go +++ b/pkg/registry/resource/resourcepoolstatusrequest/declarative_validation_test.go @@ -92,7 +92,7 @@ func TestDeclarativeValidate(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs) }) } } @@ -129,7 +129,7 @@ func TestDeclarativeValidateUpdate(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, Strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, Strategy, tc.expectedErrs) }) } } @@ -341,7 +341,7 @@ func TestDeclarativeValidateStatusUpdate(t *testing.T) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, StatusStrategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, StatusStrategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/resource/resourcepoolstatusrequest/strategy.go b/pkg/registry/resource/resourcepoolstatusrequest/strategy.go index 061e4fba4d8..4d45cc5c96c 100644 --- a/pkg/registry/resource/resourcepoolstatusrequest/strategy.go +++ b/pkg/registry/resource/resourcepoolstatusrequest/strategy.go @@ -19,7 +19,6 @@ package resourcepoolstatusrequest import ( "context" - "k8s.io/apimachinery/pkg/api/operation" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" @@ -33,12 +32,12 @@ import ( // resourcePoolStatusRequestStrategy implements behavior for ResourcePoolStatusRequest objects type resourcePoolStatusRequestStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } var ( - Strategy = &resourcePoolStatusRequestStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} + Strategy = &resourcePoolStatusRequestStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} StatusStrategy = &resourcePoolStatusRequestStatusStrategy{resourcePoolStatusRequestStrategy: Strategy} ) @@ -67,8 +66,13 @@ func (*resourcePoolStatusRequestStrategy) PrepareForCreate(ctx context.Context, func (*resourcePoolStatusRequestStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { request := obj.(*resource.ResourcePoolStatusRequest) - allErrs := validation.ValidateResourcePoolStatusRequest(request) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, nil, allErrs, operation.Create, rest.WithDeclarativeEnforcement()) + return validation.ValidateResourcePoolStatusRequest(request) +} + +// DeclarativeValidationConfig implements rest.DeclarativeValidationConfigurer to supply declarative +// validation options to the generic BeforeCreate/BeforeUpdate code path. +func (*resourcePoolStatusRequestStrategy) DeclarativeValidationConfig(ctx context.Context, obj, oldObj runtime.Object) rest.DeclarativeValidationConfig { + return rest.DeclarativeValidationConfig{DeclarativeEnforcement: true} } func (*resourcePoolStatusRequestStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { @@ -90,8 +94,7 @@ func (*resourcePoolStatusRequestStrategy) PrepareForUpdate(ctx context.Context, } func (*resourcePoolStatusRequestStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { - allErrs := validation.ValidateResourcePoolStatusRequestUpdate(obj.(*resource.ResourcePoolStatusRequest), old.(*resource.ResourcePoolStatusRequest)) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, old, allErrs, operation.Update, rest.WithDeclarativeEnforcement()) + return validation.ValidateResourcePoolStatusRequestUpdate(obj.(*resource.ResourcePoolStatusRequest), old.(*resource.ResourcePoolStatusRequest)) } func (*resourcePoolStatusRequestStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { @@ -129,8 +132,7 @@ func (*resourcePoolStatusRequestStatusStrategy) PrepareForUpdate(ctx context.Con func (r *resourcePoolStatusRequestStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { newRequest := obj.(*resource.ResourcePoolStatusRequest) oldRequest := old.(*resource.ResourcePoolStatusRequest) - allErrs := validation.ValidateResourcePoolStatusRequestStatusUpdate(newRequest, oldRequest) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, old, allErrs, operation.Update, rest.WithDeclarativeEnforcement()) + return validation.ValidateResourcePoolStatusRequestStatusUpdate(newRequest, oldRequest) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/resource/resourceslice/declarative_validation_test.go b/pkg/registry/resource/resourceslice/declarative_validation_test.go index 8494e5e5e4d..c5ee783ad58 100644 --- a/pkg/registry/resource/resourceslice/declarative_validation_test.go +++ b/pkg/registry/resource/resourceslice/declarative_validation_test.go @@ -240,7 +240,7 @@ func TestDeclarativeValidate(t *testing.T) { for k, tc := range testCases { t.Run(k, func(t *testing.T) { apitesting.VerifyValidationEquivalence( - t, ctx, &tc.input, strategy.Validate, tc.expectedErrs, + t, ctx, &tc.input, strategy, tc.expectedErrs, apitesting.WithNormalizationRules(validation.ResourceNormalizationRules...), apitesting.WithIgnoreObjectConversionErrors(), ) @@ -459,7 +459,7 @@ func TestDeclarativeValidateUpdate(t *testing.T) { t.Run(k, func(t *testing.T) { tc.old.ResourceVersion = "1" tc.update.ResourceVersion = "1" - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, strategy.ValidateUpdate, tc.expectedErrs, apitesting.WithNormalizationRules(validation.ResourceNormalizationRules...)) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.update, &tc.old, strategy, tc.expectedErrs, apitesting.WithNormalizationRules(validation.ResourceNormalizationRules...)) }) } }) diff --git a/pkg/registry/resource/resourceslice/strategy.go b/pkg/registry/resource/resourceslice/strategy.go index 9c51468246a..396760aff89 100644 --- a/pkg/registry/resource/resourceslice/strategy.go +++ b/pkg/registry/resource/resourceslice/strategy.go @@ -22,7 +22,6 @@ import ( "strings" apiequality "k8s.io/apimachinery/pkg/api/equality" - "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -41,11 +40,11 @@ import ( // resourceSliceStrategy implements behavior for ResourceSlice objects type resourceSliceStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } -var Strategy = resourceSliceStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = resourceSliceStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (resourceSliceStrategy) NamespaceScoped() bool { return false @@ -60,9 +59,13 @@ func (resourceSliceStrategy) PrepareForCreate(ctx context.Context, obj runtime.O func (resourceSliceStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { slice := obj.(*resource.ResourceSlice) - errorList := validation.ValidateResourceSlice(slice) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, slice, nil, errorList, operation.Create, rest.WithNormalizationRules(validation.ResourceNormalizationRules)) + return validation.ValidateResourceSlice(slice) +} +// DeclarativeValidationConfig implements rest.DeclarativeValidationConfigurer to supply declarative +// validation options to the generic BeforeCreate/BeforeUpdate code path. +func (resourceSliceStrategy) DeclarativeValidationConfig(ctx context.Context, obj, oldObj runtime.Object) rest.DeclarativeValidationConfig { + return rest.DeclarativeValidationConfig{NormalizationRules: validation.ResourceNormalizationRules} } // WarningsOnCreate returns warnings for the creation of the given object. @@ -98,8 +101,7 @@ func (resourceSliceStrategy) PrepareForUpdate(ctx context.Context, obj, old runt } func (resourceSliceStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { - errorList := validation.ValidateResourceSliceUpdate(obj.(*resource.ResourceSlice), old.(*resource.ResourceSlice)) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, old, errorList, operation.Update, rest.WithNormalizationRules(validation.ResourceNormalizationRules)) + return validation.ValidateResourceSliceUpdate(obj.(*resource.ResourceSlice), old.(*resource.ResourceSlice)) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/scheduling/podgroup/declarative_validation_test.go b/pkg/registry/scheduling/podgroup/declarative_validation_test.go index 2ffa55429c2..2f08190f312 100644 --- a/pkg/registry/scheduling/podgroup/declarative_validation_test.go +++ b/pkg/registry/scheduling/podgroup/declarative_validation_test.go @@ -341,7 +341,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) { features.GangScheduling: tc.enableWorkloadAwarePreemption, features.WorkloadAwarePreemption: tc.enableWorkloadAwarePreemption, }) - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, strategy.Validate, tc.expectedErrs, apitesting.WithMinEmulationVersion(version.MustParse("1.36"))) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, strategy, tc.expectedErrs, apitesting.WithMinEmulationVersion(version.MustParse("1.36"))) }) } } @@ -566,7 +566,7 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) { features.WorkloadAwarePreemption: tc.enableWorkloadAwarePreemption, }) strategy := NewStrategy() - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, strategy.ValidateUpdate, tc.expectedErrs, apitesting.WithMinEmulationVersion(version.MustParse("1.36"))) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, strategy, tc.expectedErrs, apitesting.WithMinEmulationVersion(version.MustParse("1.36"))) }) } } @@ -689,7 +689,7 @@ func testDeclarativeValidateStatusUpdate(t *testing.T, apiVersion string) { for k, tc := range testCases { t.Run(k, func(t *testing.T) { strategy := NewStatusStrategy(NewStrategy()) - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, strategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/scheduling/podgroup/strategy.go b/pkg/registry/scheduling/podgroup/strategy.go index ef86023e167..fb83a876e10 100644 --- a/pkg/registry/scheduling/podgroup/strategy.go +++ b/pkg/registry/scheduling/podgroup/strategy.go @@ -21,7 +21,6 @@ import ( "sigs.k8s.io/structured-merge-diff/v6/fieldpath" - "k8s.io/apimachinery/pkg/api/operation" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" @@ -36,14 +35,14 @@ import ( // podGroupStrategy implements behavior for PodGroup objects. type podGroupStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // NewStrategy is the default logic that applies when creating and updating PodGroup objects. func NewStrategy() *podGroupStrategy { return &podGroupStrategy{ - legacyscheme.Scheme, + rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator, } } @@ -73,7 +72,21 @@ func (*podGroupStrategy) PrepareForCreate(ctx context.Context, obj runtime.Objec func (*podGroupStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { podGroup := obj.(*scheduling.PodGroup) - allErrs := validation.ValidatePodGroup(podGroup) + return validation.ValidatePodGroup(podGroup) +} + +// DeclarativeValidationConfig implements rest.DeclarativeValidationConfigurer to supply declarative +// validation options to the generic BeforeCreate/BeforeUpdate code path. +// +// TODO: Behavior drift introduced when wiring declarative validation +// universally: the status substrategy embeds *podGroupStrategy and now +// inherits this method, so status updates pick up the full feature-gated +// options list and rest.WithDeclarativeEnforcement(). Previously the +// pre-migration inline call on the status subresource only passed +// WithDeclarativeEnforcement() (no options list). The change is additive but +// should be reviewed; if the status subresource should not see these +// options, override ValidationConfig on podGroupStatusStrategy. +func (*podGroupStrategy) DeclarativeValidationConfig(ctx context.Context, obj, oldObj runtime.Object) rest.DeclarativeValidationConfig { opts := []string{} if utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareWorkloadScheduling) { opts = append(opts, string(features.TopologyAwareWorkloadScheduling)) @@ -84,7 +97,7 @@ func (*podGroupStrategy) Validate(ctx context.Context, obj runtime.Object) field if utilfeature.DefaultFeatureGate.Enabled(features.WorkloadAwarePreemption) { opts = append(opts, string(features.WorkloadAwarePreemption)) } - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, nil, allErrs, operation.Create, rest.WithDeclarativeEnforcement(), rest.WithOptions(opts)) + return rest.DeclarativeValidationConfig{DeclarativeEnforcement: true, Options: opts} } func (*podGroupStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { @@ -107,22 +120,7 @@ func (*podGroupStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime. func (*podGroupStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { newPodGroup := obj.(*scheduling.PodGroup) oldPodGroup := old.(*scheduling.PodGroup) - allErrs := validation.ValidatePodGroupUpdate(newPodGroup, oldPodGroup) - opts := []string{} - // Declarative validation will always allow fields to remain unchanged, so if any - // of the fields which are covered by these gates are set, we will not re-validate them - // (even if the gates are disabled) as long as they do not change values. If a gate - // is disabled, they will not be allowed to change values. - if utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareWorkloadScheduling) { - opts = append(opts, string(features.TopologyAwareWorkloadScheduling)) - } - if utilfeature.DefaultFeatureGate.Enabled(features.DRAWorkloadResourceClaims) { - opts = append(opts, string(features.DRAWorkloadResourceClaims)) - } - if utilfeature.DefaultFeatureGate.Enabled(features.WorkloadAwarePreemption) { - opts = append(opts, string(features.WorkloadAwarePreemption)) - } - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newPodGroup, oldPodGroup, allErrs, operation.Update, rest.WithDeclarativeEnforcement(), rest.WithOptions(opts)) + return validation.ValidatePodGroupUpdate(newPodGroup, oldPodGroup) } func (*podGroupStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { @@ -166,8 +164,7 @@ func (*podGroupStatusStrategy) PrepareForUpdate(ctx context.Context, obj, old ru func (r *podGroupStatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { newPodGroup := obj.(*scheduling.PodGroup) oldPodGroup := old.(*scheduling.PodGroup) - errs := validation.ValidatePodGroupStatusUpdate(newPodGroup, oldPodGroup) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, newPodGroup, oldPodGroup, errs, operation.Update, rest.WithDeclarativeEnforcement()) + return validation.ValidatePodGroupStatusUpdate(newPodGroup, oldPodGroup) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/scheduling/priorityclass/strategy.go b/pkg/registry/scheduling/priorityclass/strategy.go index 462a5c2f346..afe17ef8456 100644 --- a/pkg/registry/scheduling/priorityclass/strategy.go +++ b/pkg/registry/scheduling/priorityclass/strategy.go @@ -21,6 +21,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/scheduling" @@ -29,12 +30,12 @@ import ( // priorityClassStrategy implements verification logic for PriorityClass. type priorityClassStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating PriorityClass objects. -var Strategy = priorityClassStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = priorityClassStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} // NamespaceScoped returns false because all PriorityClasses are global. func (priorityClassStrategy) NamespaceScoped() bool { diff --git a/pkg/registry/scheduling/workload/declarative_validation_test.go b/pkg/registry/scheduling/workload/declarative_validation_test.go index bb58d82331e..7a3b98186ee 100644 --- a/pkg/registry/scheduling/workload/declarative_validation_test.go +++ b/pkg/registry/scheduling/workload/declarative_validation_test.go @@ -359,7 +359,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) { features.GangScheduling: tc.enableWorkloadAwarePreemption, features.WorkloadAwarePreemption: tc.enableWorkloadAwarePreemption, }) - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs, apitesting.WithMinEmulationVersion(version.MustParse("1.36"))) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs, apitesting.WithMinEmulationVersion(version.MustParse("1.36"))) }) } } @@ -605,7 +605,7 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) { IsResourceRequest: true, Verb: "update", }) - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, Strategy.ValidateUpdate, tc.expectedErrs, apitesting.WithMinEmulationVersion(version.MustParse("1.36"))) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, Strategy, tc.expectedErrs, apitesting.WithMinEmulationVersion(version.MustParse("1.36"))) }) } } diff --git a/pkg/registry/scheduling/workload/strategy.go b/pkg/registry/scheduling/workload/strategy.go index b42531fb494..61b30deba94 100644 --- a/pkg/registry/scheduling/workload/strategy.go +++ b/pkg/registry/scheduling/workload/strategy.go @@ -19,7 +19,6 @@ package workload import ( "context" - "k8s.io/apimachinery/pkg/api/operation" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/rest" @@ -33,12 +32,12 @@ import ( // workloadStrategy implements behavior for Workload objects. type workloadStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating Workload objects. -var Strategy = workloadStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = workloadStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (workloadStrategy) NamespaceScoped() bool { return true @@ -50,7 +49,12 @@ func (workloadStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object func (workloadStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { workloadScheduling := obj.(*scheduling.Workload) - allErrs := validation.ValidateWorkload(workloadScheduling) + return validation.ValidateWorkload(workloadScheduling) +} + +// DeclarativeValidationConfig implements rest.DeclarativeValidationConfigurer to supply declarative +// validation options to the generic BeforeCreate/BeforeUpdate code path. +func (workloadStrategy) DeclarativeValidationConfig(ctx context.Context, obj, oldObj runtime.Object) rest.DeclarativeValidationConfig { opts := []string{} if utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareWorkloadScheduling) { opts = append(opts, string(features.TopologyAwareWorkloadScheduling)) @@ -61,7 +65,7 @@ func (workloadStrategy) Validate(ctx context.Context, obj runtime.Object) field. if utilfeature.DefaultFeatureGate.Enabled(features.WorkloadAwarePreemption) { opts = append(opts, string(features.WorkloadAwarePreemption)) } - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, nil, allErrs, operation.Create, rest.WithDeclarativeEnforcement(), rest.WithOptions(opts)) + return rest.DeclarativeValidationConfig{DeclarativeEnforcement: true, Options: opts} } func (workloadStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { @@ -79,22 +83,7 @@ func (workloadStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.O } func (workloadStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { - allErrs := validation.ValidateWorkloadUpdate(obj.(*scheduling.Workload), old.(*scheduling.Workload)) - opts := []string{} - // Declarative validation will always allow fields to remain unchanged, so if any - // of the fields which are covered by these gates are set, we will not re-validate them - // (even if the gates are disabled) as long as they do not change values. If a gate - // is disabled, they will not be allowed to change values. - if utilfeature.DefaultFeatureGate.Enabled(features.TopologyAwareWorkloadScheduling) { - opts = append(opts, string(features.TopologyAwareWorkloadScheduling)) - } - if utilfeature.DefaultFeatureGate.Enabled(features.DRAWorkloadResourceClaims) { - opts = append(opts, string(features.DRAWorkloadResourceClaims)) - } - if utilfeature.DefaultFeatureGate.Enabled(features.WorkloadAwarePreemption) { - opts = append(opts, string(features.WorkloadAwarePreemption)) - } - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, old, allErrs, operation.Update, rest.WithDeclarativeEnforcement(), rest.WithOptions(opts)) + return validation.ValidateWorkloadUpdate(obj.(*scheduling.Workload), old.(*scheduling.Workload)) } func (workloadStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { diff --git a/pkg/registry/storage/csidriver/strategy.go b/pkg/registry/storage/csidriver/strategy.go index 510784acbe3..0679fe68e34 100644 --- a/pkg/registry/storage/csidriver/strategy.go +++ b/pkg/registry/storage/csidriver/strategy.go @@ -22,6 +22,7 @@ import ( apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" utilfeature "k8s.io/apiserver/pkg/util/feature" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -36,13 +37,13 @@ const ( // csiDriverStrategy implements behavior for CSIDriver objects type csiDriverStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating // CSIDriver objects via the REST API. -var Strategy = csiDriverStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = csiDriverStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (csiDriverStrategy) NamespaceScoped() bool { return false diff --git a/pkg/registry/storage/csinode/strategy.go b/pkg/registry/storage/csinode/strategy.go index 3caf9395518..37c05297009 100644 --- a/pkg/registry/storage/csinode/strategy.go +++ b/pkg/registry/storage/csinode/strategy.go @@ -21,6 +21,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/storage" @@ -29,13 +30,13 @@ import ( // csiNodeStrategy implements behavior for CSINode objects type csiNodeStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating // CSINode objects via the REST API. -var Strategy = csiNodeStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = csiNodeStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (csiNodeStrategy) NamespaceScoped() bool { return false diff --git a/pkg/registry/storage/csistoragecapacity/strategy.go b/pkg/registry/storage/csistoragecapacity/strategy.go index 8de5e5d5ec6..538f3dddb09 100644 --- a/pkg/registry/storage/csistoragecapacity/strategy.go +++ b/pkg/registry/storage/csistoragecapacity/strategy.go @@ -22,6 +22,7 @@ import ( metav1validation "k8s.io/apimachinery/pkg/apis/meta/v1/validation" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" storageutil "k8s.io/kubernetes/pkg/api/storage" @@ -31,13 +32,13 @@ import ( // csiStorageCapacityStrategy implements behavior for CSIStorageCapacity objects type csiStorageCapacityStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating // CSIStorageCapacity objects via the REST API. -var Strategy = csiStorageCapacityStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = csiStorageCapacityStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (csiStorageCapacityStrategy) NamespaceScoped() bool { return true diff --git a/pkg/registry/storage/storageclass/declarative_validation_test.go b/pkg/registry/storage/storageclass/declarative_validation_test.go index 4e1f717179a..a0b5dba3e04 100644 --- a/pkg/registry/storage/storageclass/declarative_validation_test.go +++ b/pkg/registry/storage/storageclass/declarative_validation_test.go @@ -65,7 +65,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) { } for k, tc := range testCases { t.Run(k, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs) }) } } @@ -188,7 +188,7 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) { IsResourceRequest: true, Verb: "update", }) - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, Strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.updateObj, &tc.oldObj, Strategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/storage/storageclass/strategy.go b/pkg/registry/storage/storageclass/strategy.go index 8634170f2ce..064a7ef19ed 100644 --- a/pkg/registry/storage/storageclass/strategy.go +++ b/pkg/registry/storage/storageclass/strategy.go @@ -18,7 +18,7 @@ package storageclass import ( "context" - "k8s.io/apimachinery/pkg/api/operation" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apimachinery/pkg/runtime" @@ -32,13 +32,13 @@ import ( // storageClassStrategy implements behavior for StorageClass objects type storageClassStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating // StorageClass objects via the REST API. -var Strategy = storageClassStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = storageClassStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (storageClassStrategy) NamespaceScoped() bool { return false @@ -50,8 +50,7 @@ func (storageClassStrategy) PrepareForCreate(ctx context.Context, obj runtime.Ob func (storageClassStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { storageClass := obj.(*storage.StorageClass) - allErrs := validation.ValidateStorageClass(storageClass) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, nil, allErrs, operation.Create) + return validation.ValidateStorageClass(storageClass) } // WarningsOnCreate returns warnings for the creation of the given object. @@ -74,7 +73,7 @@ func (storageClassStrategy) PrepareForUpdate(ctx context.Context, obj, old runti func (storageClassStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { allErrs := validation.ValidateStorageClass(obj.(*storage.StorageClass)) allErrs = append(allErrs, validation.ValidateStorageClassUpdate(obj.(*storage.StorageClass), old.(*storage.StorageClass))...) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, old, allErrs, operation.Update) + return allErrs } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/storage/volumeattachment/declarative_validation_test.go b/pkg/registry/storage/volumeattachment/declarative_validation_test.go index 03bfeb6f7ac..60b90b53ace 100644 --- a/pkg/registry/storage/volumeattachment/declarative_validation_test.go +++ b/pkg/registry/storage/volumeattachment/declarative_validation_test.go @@ -89,7 +89,7 @@ func testDeclarativeValidate(t *testing.T, apiVersion string) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { - apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy.Validate, tc.expectedErrs) + apitesting.VerifyValidationEquivalence(t, ctx, &tc.input, Strategy, tc.expectedErrs) }) } } @@ -123,7 +123,7 @@ func testDeclarativeValidateUpdate(t *testing.T, apiVersion string) { for name, tc := range testCases { t.Run(name, func(t *testing.T) { - apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.newInput, &tc.oldInput, Strategy.ValidateUpdate, tc.expectedErrs) + apitesting.VerifyUpdateValidationEquivalence(t, ctx, &tc.newInput, &tc.oldInput, Strategy, tc.expectedErrs) }) } } diff --git a/pkg/registry/storage/volumeattachment/strategy.go b/pkg/registry/storage/volumeattachment/strategy.go index 4f0d41013bb..28014a143ba 100644 --- a/pkg/registry/storage/volumeattachment/strategy.go +++ b/pkg/registry/storage/volumeattachment/strategy.go @@ -18,7 +18,7 @@ package volumeattachment import ( "context" - "k8s.io/apimachinery/pkg/api/operation" + "k8s.io/apiserver/pkg/registry/rest" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -35,13 +35,13 @@ import ( // volumeAttachmentStrategy implements behavior for VolumeAttachment objects type volumeAttachmentStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating // VolumeAttachment objects via the REST API. -var Strategy = volumeAttachmentStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = volumeAttachmentStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (volumeAttachmentStrategy) NamespaceScoped() bool { return false @@ -67,8 +67,7 @@ func (volumeAttachmentStrategy) PrepareForCreate(ctx context.Context, obj runtim func (volumeAttachmentStrategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { volumeAttachment := obj.(*storage.VolumeAttachment) - errs := validation.ValidateVolumeAttachment(volumeAttachment) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, nil, errs, operation.Create) + return validation.ValidateVolumeAttachment(volumeAttachment) } // WarningsOnCreate returns warnings for the creation of the given object. @@ -97,8 +96,7 @@ func (volumeAttachmentStrategy) PrepareForUpdate(ctx context.Context, obj, old r func (volumeAttachmentStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { newVolumeAttachmentObj := obj.(*storage.VolumeAttachment) oldVolumeAttachmentObj := old.(*storage.VolumeAttachment) - allErrs := validation.ValidateVolumeAttachmentUpdate(newVolumeAttachmentObj, oldVolumeAttachmentObj) - return rest.ValidateDeclarativelyWithMigrationChecks(ctx, legacyscheme.Scheme, obj, old, allErrs, operation.Update) + return validation.ValidateVolumeAttachmentUpdate(newVolumeAttachmentObj, oldVolumeAttachmentObj) } // WarningsOnUpdate returns warnings for the given update. diff --git a/pkg/registry/storage/volumeattributesclass/strategy.go b/pkg/registry/storage/volumeattributesclass/strategy.go index f7652bc46a4..ab51d861286 100644 --- a/pkg/registry/storage/volumeattributesclass/strategy.go +++ b/pkg/registry/storage/volumeattributesclass/strategy.go @@ -21,6 +21,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage/names" "k8s.io/kubernetes/pkg/api/legacyscheme" "k8s.io/kubernetes/pkg/apis/storage" @@ -29,13 +30,13 @@ import ( // volumeAttributesClassStrategy implements behavior for VolumeAttributesClassStrategy objects type volumeAttributesClassStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the default logic that applies when creating and updating // VolumeAttributesClass objects via the REST API. -var Strategy = volumeAttributesClassStrategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = volumeAttributesClassStrategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} func (volumeAttributesClassStrategy) NamespaceScoped() bool { return false diff --git a/pkg/registry/storagemigration/storagemigration/strategy.go b/pkg/registry/storagemigration/storagemigration/strategy.go index 330a6d9224c..38c8c2c1c25 100644 --- a/pkg/registry/storagemigration/storagemigration/strategy.go +++ b/pkg/registry/storagemigration/storagemigration/strategy.go @@ -35,12 +35,12 @@ import ( // strategy implements behavior for ClusterTrustBundles. type strategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator } // Strategy is the create, update, and delete strategy for ClusterTrustBundles. -var Strategy = strategy{legacyscheme.Scheme, names.SimpleNameGenerator} +var Strategy = strategy{rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator} var _ rest.RESTCreateStrategy = Strategy var _ rest.RESTUpdateStrategy = Strategy diff --git a/pkg/registry/testapigroup/carp/strategy.go b/pkg/registry/testapigroup/carp/strategy.go index 689ab03adfa..dcc56870e02 100644 --- a/pkg/registry/testapigroup/carp/strategy.go +++ b/pkg/registry/testapigroup/carp/strategy.go @@ -27,6 +27,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/validation/field" "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/registry/rest" "k8s.io/apiserver/pkg/storage" "k8s.io/apiserver/pkg/storage/names" v1 "k8s.io/client-go/kubernetes/typed/core/v1" @@ -36,7 +37,7 @@ import ( // carpStrategy implements behavior for Carp objects type carpStrategy struct { - runtime.ObjectTyper + rest.DeclarativeValidation names.NameGenerator nsClient v1.NamespaceInterface } @@ -44,7 +45,7 @@ type carpStrategy struct { // NewStrategy is the default logic that applies when creating and updating Carp objects. func NewStrategy(nsClient v1.NamespaceInterface) *carpStrategy { return &carpStrategy{ - legacyscheme.Scheme, + rest.DeclarativeValidation{Scheme: legacyscheme.Scheme}, names.SimpleNameGenerator, nsClient, }