From fb910cd593e57d45940a9a78939b3650ac386dc6 Mon Sep 17 00:00:00 2001 From: Kevin Delgado Date: Tue, 19 Oct 2021 18:49:44 +0000 Subject: [PATCH] Add feature gate for FieldValidation --- pkg/features/kube_features.go | 1 + .../k8s.io/apiserver/pkg/endpoints/handlers/rest.go | 4 ++++ .../k8s.io/apiserver/pkg/features/kube_features.go | 8 ++++++++ test/integration/apiserver/field_validation_test.go | 12 ++++++++++-- 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/pkg/features/kube_features.go b/pkg/features/kube_features.go index 8c4d8253b0d97..e5d0ba2eebc34 100644 --- a/pkg/features/kube_features.go +++ b/pkg/features/kube_features.go @@ -904,6 +904,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS genericfeatures.WarningHeaders: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.24 genericfeatures.OpenAPIEnums: {Default: false, PreRelease: featuregate.Alpha}, genericfeatures.CustomResourceValidationExpressions: {Default: false, PreRelease: featuregate.Alpha}, + genericfeatures.FieldValidation: {Default: false, PreRelease: featuregate.Alpha}, // features that enable backwards compatibility but are scheduled to be removed // ... HPAScaleToZero: {Default: false, PreRelease: featuregate.Alpha}, diff --git a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/rest.go b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/rest.go index 9b8fca91f0c05..f079f4eb2a288 100644 --- a/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/rest.go +++ b/staging/src/k8s.io/apiserver/pkg/endpoints/handlers/rest.go @@ -463,6 +463,10 @@ func isDryRun(url *url.URL) bool { // media type, because the list of media types that support field validation are a subset of // all supported media types (protobuf does not support field validation). func fieldValidation(req *http.Request) (runtime.FieldValidationDirective, error) { + if !utilfeature.DefaultFeatureGate.Enabled(features.FieldValidation) { + return runtime.IgnoreFieldValidation, nil + } + supportedContentTypes := []string{runtime.ContentTypeJSON, runtime.ContentTypeJSONMergePatch, runtime.ContentTypeJSONStrategicMergePatch, runtime.ContentTypeYAML} contentType := req.Header.Get("Content-Type") // TODO: not sure if it is okay to assume empty content type is a valid one diff --git a/staging/src/k8s.io/apiserver/pkg/features/kube_features.go b/staging/src/k8s.io/apiserver/pkg/features/kube_features.go index d0da61e57b955..29768ea9015f0 100644 --- a/staging/src/k8s.io/apiserver/pkg/features/kube_features.go +++ b/staging/src/k8s.io/apiserver/pkg/features/kube_features.go @@ -185,6 +185,13 @@ const ( // // Enables expression validation for Custom Resource CustomResourceValidationExpressions featuregate.Feature = "CustomResourceValidationExpressions" + + // owner: @kevindelgado + // kep: http://kep.k8s.io/2885 + // alpha: v1.23 + // + // Enables server-side field validation. + FieldValidation featuregate.Feature = "FieldValidation" ) func init() { @@ -215,4 +222,5 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS APIServerTracing: {Default: false, PreRelease: featuregate.Alpha}, OpenAPIEnums: {Default: false, PreRelease: featuregate.Alpha}, CustomResourceValidationExpressions: {Default: false, PreRelease: featuregate.Alpha}, + FieldValidation: {Default: false, PreRelease: featuregate.Alpha}, } diff --git a/test/integration/apiserver/field_validation_test.go b/test/integration/apiserver/field_validation_test.go index 24d275de7582e..52a88258d1ad5 100644 --- a/test/integration/apiserver/field_validation_test.go +++ b/test/integration/apiserver/field_validation_test.go @@ -45,7 +45,7 @@ import ( // TestFieldValidationPost tests POST requests containing unknown fields with // strict and non-strict field validation. func TestFieldValidationPost(t *testing.T) { - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServerSideApply, true)() + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.FieldValidation, true)() _, client, closeFn := setup(t) defer closeFn() @@ -120,7 +120,7 @@ func TestFieldValidationPost(t *testing.T) { // TestFieldValidationPut tests PUT requests containing unknown fields with // strict and non-strict field validation. func TestFieldValidationPut(t *testing.T) { - defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServerSideApply, true)() + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.FieldValidation, true)() _, client, closeFn := setup(t) defer closeFn() @@ -210,6 +210,8 @@ func TestFieldValidationPut(t *testing.T) { // Benchmark field validation for strict vs non-strict func BenchmarkFieldValidationPostPut(b *testing.B) { + defer featuregatetesting.SetFeatureGateDuringTest(b, utilfeature.DefaultFeatureGate, features.FieldValidation, true)() + _, client, closeFn := setup(b) defer closeFn() @@ -384,6 +386,7 @@ type smpTestCase struct { // but succeeds when fieldValidation is ignored. func TestFieldValidationSMP(t *testing.T) { defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ServerSideApply, true)() + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.FieldValidation, true)() _, client, closeFn := setup(t) defer closeFn() @@ -420,6 +423,7 @@ func TestFieldValidationSMP(t *testing.T) { // Benchmark strategic-merge-patch field validation for strict vs non-strict func BenchmarkFieldValidationSMP(b *testing.B) { defer featuregatetesting.SetFeatureGateDuringTest(b, utilfeature.DefaultFeatureGate, features.ServerSideApply, true)() + defer featuregatetesting.SetFeatureGateDuringTest(b, utilfeature.DefaultFeatureGate, features.FieldValidation, true)() _, client, closeFn := setup(b) defer closeFn() @@ -513,6 +517,8 @@ func patchCRDTestSetup(t testing.TB, server kubeapiservertesting.TestServer, nam // TestFieldValidationPatchCRD tests that server-side schema validation // works for jsonpatch and mergepatch requests. func TestFieldValidationPatchCRD(t *testing.T) { + defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.FieldValidation, true)() + var testcases = []struct { name string patchType types.PatchType @@ -600,6 +606,8 @@ func TestFieldValidationPatchCRD(t *testing.T) { // Benchmark patch CRD for strict vs non-strict func BenchmarkFieldValidationPatchCRD(b *testing.B) { + defer featuregatetesting.SetFeatureGateDuringTest(b, utilfeature.DefaultFeatureGate, features.FieldValidation, true)() + benchmarks := []struct { name string patchType types.PatchType