Merge pull request #128539 from benluddy/cbor-feature-gates

KEP-4222: Add CBOR feature gates.

Kubernetes-commit: a28f14089cfa47ef9c57f9f283e1504a68f616d6
This commit is contained in:
Kubernetes Publisher 2024-11-05 23:21:56 +00:00
commit 04fa4ade1a
10 changed files with 17 additions and 37 deletions

2
go.mod
View File

@ -52,7 +52,7 @@ require (
gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/square/go-jose.v2 v2.6.0
k8s.io/api v0.0.0-20241105230147-1ddf895d7e74 k8s.io/api v0.0.0-20241105230147-1ddf895d7e74
k8s.io/apimachinery v0.0.0-20241105225905-b5e810677b4f k8s.io/apimachinery v0.0.0-20241105225905-b5e810677b4f
k8s.io/client-go v0.0.0-20241105230542-c1010ffd7de3 k8s.io/client-go v0.0.0-20241106030549-9d76eb1606c5
k8s.io/component-base v0.0.0-20241105231555-33a822ed3833 k8s.io/component-base v0.0.0-20241105231555-33a822ed3833
k8s.io/klog/v2 v2.130.1 k8s.io/klog/v2 v2.130.1
k8s.io/kms v0.0.0-20241101191923-aa635f2d841b k8s.io/kms v0.0.0-20241101191923-aa635f2d841b

4
go.sum
View File

@ -367,8 +367,8 @@ k8s.io/api v0.0.0-20241105230147-1ddf895d7e74 h1:omoqr99s5DbyApsEajh0iIyKzGL/5vk
k8s.io/api v0.0.0-20241105230147-1ddf895d7e74/go.mod h1:QMjNGKwUJOiB0TWCMJWLvhiVAvOrl9I+MTeV0dr56NE= k8s.io/api v0.0.0-20241105230147-1ddf895d7e74/go.mod h1:QMjNGKwUJOiB0TWCMJWLvhiVAvOrl9I+MTeV0dr56NE=
k8s.io/apimachinery v0.0.0-20241105225905-b5e810677b4f h1:MTmedS366tu07Nh6HBoXS90/6DA5gP62gMyYTF+lT+Q= k8s.io/apimachinery v0.0.0-20241105225905-b5e810677b4f h1:MTmedS366tu07Nh6HBoXS90/6DA5gP62gMyYTF+lT+Q=
k8s.io/apimachinery v0.0.0-20241105225905-b5e810677b4f/go.mod h1:HqhdaJUgQqky29T1V0o2yFkt/pZqLFIDyn9Zi/8rxoY= k8s.io/apimachinery v0.0.0-20241105225905-b5e810677b4f/go.mod h1:HqhdaJUgQqky29T1V0o2yFkt/pZqLFIDyn9Zi/8rxoY=
k8s.io/client-go v0.0.0-20241105230542-c1010ffd7de3 h1:ZgoctdRlDLgbqPdEdcgyoyBbVGgNmfcokEkFYjpHZ68= k8s.io/client-go v0.0.0-20241106030549-9d76eb1606c5 h1:TKKepvH+s8JURpM+nwV6fwfJu8LEL1aJxYiCssL9Wac=
k8s.io/client-go v0.0.0-20241105230542-c1010ffd7de3/go.mod h1:p8opQH8f5aM1YzHrN0yWNcD4qqfAJIaR0+kVTU/TIBw= k8s.io/client-go v0.0.0-20241106030549-9d76eb1606c5/go.mod h1:p8opQH8f5aM1YzHrN0yWNcD4qqfAJIaR0+kVTU/TIBw=
k8s.io/component-base v0.0.0-20241105231555-33a822ed3833 h1:85DceDhD40wu9EBtSDCkSHnYB1Lx0hVgu4pj/ZQLioU= k8s.io/component-base v0.0.0-20241105231555-33a822ed3833 h1:85DceDhD40wu9EBtSDCkSHnYB1Lx0hVgu4pj/ZQLioU=
k8s.io/component-base v0.0.0-20241105231555-33a822ed3833/go.mod h1:LiXjb6P40r1C7CAwQfD9HDBX7LzkVHFgYJOzj1oaFO4= k8s.io/component-base v0.0.0-20241105231555-33a822ed3833/go.mod h1:LiXjb6P40r1C7CAwQfD9HDBX7LzkVHFgYJOzj1oaFO4=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=

View File

@ -138,7 +138,7 @@ func PatchResource(r rest.Patcher, scope *RequestScope, admit admission.Interfac
case types.ApplyYAMLPatchType: case types.ApplyYAMLPatchType:
baseContentType = runtime.ContentTypeYAML baseContentType = runtime.ContentTypeYAML
case types.ApplyCBORPatchType: case types.ApplyCBORPatchType:
if !utilfeature.TestOnlyFeatureGate.Enabled(features.TestOnlyCBORServingAndStorage) { if !utilfeature.DefaultFeatureGate.Enabled(features.CBORServingAndStorage) {
// This request should have already been rejected by the // This request should have already been rejected by the
// Content-Type allowlist check. Return 500 because assumptions are // Content-Type allowlist check. Return 500 because assumptions are
// already broken and the feature is not GA. // already broken and the feature is not GA.
@ -673,7 +673,7 @@ func (p *patcher) patchResource(ctx context.Context, scope *RequestScope) (runti
p.mechanism = newApplyPatcher(p, scope.FieldManager, yaml.Unmarshal, yaml.UnmarshalStrict) p.mechanism = newApplyPatcher(p, scope.FieldManager, yaml.Unmarshal, yaml.UnmarshalStrict)
p.forceAllowCreate = true p.forceAllowCreate = true
case types.ApplyCBORPatchType: case types.ApplyCBORPatchType:
if !utilfeature.TestOnlyFeatureGate.Enabled(features.TestOnlyCBORServingAndStorage) { if !utilfeature.DefaultFeatureGate.Enabled(features.CBORServingAndStorage) {
utilruntime.HandleErrorWithContext(context.TODO(), nil, "CBOR apply requests should be rejected before reaching this point unless the feature gate is enabled.") utilruntime.HandleErrorWithContext(context.TODO(), nil, "CBOR apply requests should be rejected before reaching this point unless the feature gate is enabled.")
return nil, false, fmt.Errorf("%v: unimplemented patch type", p.patchType) return nil, false, fmt.Errorf("%v: unimplemented patch type", p.patchType)
} }

View File

@ -286,7 +286,7 @@ func WriteObjectNegotiated(s runtime.NegotiatedSerializer, restrictions negotiat
audit.LogResponseObject(req.Context(), object, gv, s) audit.LogResponseObject(req.Context(), object, gv, s)
var encoder runtime.Encoder var encoder runtime.Encoder
if utilfeature.TestOnlyFeatureGate.Enabled(features.TestOnlyCBORServingAndStorage) { if utilfeature.DefaultFeatureGate.Enabled(features.CBORServingAndStorage) {
encoder = s.EncoderForVersion(runtime.UseNondeterministicEncoding(serializer.Serializer), gv) encoder = s.EncoderForVersion(runtime.UseNondeterministicEncoding(serializer.Serializer), gv)
} else { } else {
encoder = s.EncoderForVersion(serializer.Serializer, gv) encoder = s.EncoderForVersion(serializer.Serializer, gv)

View File

@ -77,7 +77,7 @@ func serveWatchHandler(watcher watch.Interface, scope *RequestScope, mediaTypeOp
} }
framer := serializer.StreamSerializer.Framer framer := serializer.StreamSerializer.Framer
var encoder runtime.Encoder var encoder runtime.Encoder
if utilfeature.TestOnlyFeatureGate.Enabled(features.TestOnlyCBORServingAndStorage) { if utilfeature.DefaultFeatureGate.Enabled(features.CBORServingAndStorage) {
encoder = scope.Serializer.EncoderForVersion(runtime.UseNondeterministicEncoding(serializer.StreamSerializer.Serializer), scope.Kind.GroupVersion()) encoder = scope.Serializer.EncoderForVersion(runtime.UseNondeterministicEncoding(serializer.StreamSerializer.Serializer), scope.Kind.GroupVersion())
} else { } else {
encoder = scope.Serializer.EncoderForVersion(serializer.StreamSerializer.Serializer, scope.Kind.GroupVersion()) encoder = scope.Serializer.EncoderForVersion(serializer.StreamSerializer.Serializer, scope.Kind.GroupVersion())
@ -102,13 +102,13 @@ func serveWatchHandler(watcher watch.Interface, scope *RequestScope, mediaTypeOp
if !ok { if !ok {
return nil, fmt.Errorf("no encoder for %q exists in the requested target %#v", serializer.MediaType, contentSerializer) return nil, fmt.Errorf("no encoder for %q exists in the requested target %#v", serializer.MediaType, contentSerializer)
} }
if utilfeature.TestOnlyFeatureGate.Enabled(features.TestOnlyCBORServingAndStorage) { if utilfeature.DefaultFeatureGate.Enabled(features.CBORServingAndStorage) {
negotiatedEncoder = contentSerializer.EncoderForVersion(runtime.UseNondeterministicEncoding(info.Serializer), contentKind.GroupVersion()) negotiatedEncoder = contentSerializer.EncoderForVersion(runtime.UseNondeterministicEncoding(info.Serializer), contentKind.GroupVersion())
} else { } else {
negotiatedEncoder = contentSerializer.EncoderForVersion(info.Serializer, contentKind.GroupVersion()) negotiatedEncoder = contentSerializer.EncoderForVersion(info.Serializer, contentKind.GroupVersion())
} }
} else { } else {
if utilfeature.TestOnlyFeatureGate.Enabled(features.TestOnlyCBORServingAndStorage) { if utilfeature.DefaultFeatureGate.Enabled(features.CBORServingAndStorage) {
negotiatedEncoder = scope.Serializer.EncoderForVersion(runtime.UseNondeterministicEncoding(serializer.Serializer), contentKind.GroupVersion()) negotiatedEncoder = scope.Serializer.EncoderForVersion(runtime.UseNondeterministicEncoding(serializer.Serializer), contentKind.GroupVersion())
} else { } else {
negotiatedEncoder = scope.Serializer.EncoderForVersion(serializer.Serializer, contentKind.GroupVersion()) negotiatedEncoder = scope.Serializer.EncoderForVersion(serializer.Serializer, contentKind.GroupVersion())

View File

@ -895,7 +895,7 @@ func (a *APIInstaller) registerResourceHandlers(path string, storage rest.Storag
string(types.StrategicMergePatchType), string(types.StrategicMergePatchType),
string(types.ApplyYAMLPatchType), string(types.ApplyYAMLPatchType),
} }
if utilfeature.TestOnlyFeatureGate.Enabled(features.TestOnlyCBORServingAndStorage) { if utilfeature.DefaultFeatureGate.Enabled(features.CBORServingAndStorage) {
supportedTypes = append(supportedTypes, string(types.ApplyCBORPatchType)) supportedTypes = append(supportedTypes, string(types.ApplyCBORPatchType))
} }
handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulPatchResource(patcher, reqScope, admit, supportedTypes)) handler := metrics.InstrumentRouteFunc(action.Verb, group, version, resource, subresource, requestScope, metrics.APIServerComponent, deprecated, removedRelease, restfulPatchResource(patcher, reqScope, admit, supportedTypes))

View File

@ -92,9 +92,7 @@ const (
// //
// Enables CBOR as a supported encoding for requests and responses, and as the // Enables CBOR as a supported encoding for requests and responses, and as the
// preferred storage encoding for custom resources. // preferred storage encoding for custom resources.
// CBORServingAndStorage featuregate.Feature = "CBORServingAndStorage"
// This feature is currently PRE-ALPHA and MUST NOT be enabled outside of integration tests.
TestOnlyCBORServingAndStorage featuregate.Feature = "TestOnlyCBORServingAndStorage"
// owner: @serathius // owner: @serathius
// //
@ -245,7 +243,6 @@ const (
func init() { func init() {
runtime.Must(utilfeature.DefaultMutableFeatureGate.Add(defaultKubernetesFeatureGates)) runtime.Must(utilfeature.DefaultMutableFeatureGate.Add(defaultKubernetesFeatureGates))
runtime.Must(utilfeature.DefaultMutableFeatureGate.AddVersioned(defaultVersionedKubernetesFeatureGates)) runtime.Must(utilfeature.DefaultMutableFeatureGate.AddVersioned(defaultVersionedKubernetesFeatureGates))
runtime.Must(utilfeature.TestOnlyMutableFeatureGate.AddVersioned(testOnlyVersionedKubernetesFeatureGates))
} }
// defaultVersionedKubernetesFeatureGates consists of all known Kubernetes-specific feature keys with VersionedSpecs. // defaultVersionedKubernetesFeatureGates consists of all known Kubernetes-specific feature keys with VersionedSpecs.
@ -306,6 +303,10 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.32"), Default: true, PreRelease: featuregate.Beta}, {Version: version.MustParse("1.32"), Default: true, PreRelease: featuregate.Beta},
}, },
CBORServingAndStorage: {
{Version: version.MustParse("1.32"), Default: false, PreRelease: featuregate.Alpha},
},
ConcurrentWatchObjectDecode: { ConcurrentWatchObjectDecode: {
{Version: version.MustParse("1.31"), Default: false, PreRelease: featuregate.Beta}, {Version: version.MustParse("1.31"), Default: false, PreRelease: featuregate.Beta},
}, },
@ -417,12 +418,3 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
// defaultKubernetesFeatureGates consists of legacy unversioned Kubernetes-specific feature keys. // defaultKubernetesFeatureGates consists of legacy unversioned Kubernetes-specific feature keys.
// Please do not add to this struct and use defaultVersionedKubernetesFeatureGates instead. // Please do not add to this struct and use defaultVersionedKubernetesFeatureGates instead.
var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{} var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{}
// testOnlyVersionedKubernetesFeatureGates consists of features that require programmatic enablement
// for integration testing, but have not yet graduated to alpha in a release and must not be enabled
// by a runtime option.
var testOnlyVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate.VersionedSpecs{
TestOnlyCBORServingAndStorage: {
{Version: version.MustParse("1.32"), Default: false, PreRelease: featuregate.Alpha},
},
}

View File

@ -756,7 +756,7 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G
return nil, fmt.Errorf("Genericapiserver.New() called with config.Serializer == nil") return nil, fmt.Errorf("Genericapiserver.New() called with config.Serializer == nil")
} }
allowedMediaTypes := defaultAllowedMediaTypes allowedMediaTypes := defaultAllowedMediaTypes
if utilfeature.TestOnlyFeatureGate.Enabled(genericfeatures.TestOnlyCBORServingAndStorage) { if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.CBORServingAndStorage) {
allowedMediaTypes = append(allowedMediaTypes, runtime.ContentTypeCBOR) allowedMediaTypes = append(allowedMediaTypes, runtime.ContentTypeCBOR)
} }
for _, info := range c.Serializer.SupportedMediaTypes() { for _, info := range c.Serializer.SupportedMediaTypes() {

View File

@ -424,7 +424,7 @@ func TestNewErrorForbiddenSerializer(t *testing.T) {
} }
func TestNewFeatureGatedSerializer(t *testing.T) { func TestNewFeatureGatedSerializer(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.TestOnlyFeatureGate, features.TestOnlyCBORServingAndStorage, true) featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.CBORServingAndStorage, true)
config := NewConfig(serializer.NewCodecFactory(scheme, serializer.WithSerializer(func(creater runtime.ObjectCreater, typer runtime.ObjectTyper) runtime.SerializerInfo { config := NewConfig(serializer.NewCodecFactory(scheme, serializer.WithSerializer(func(creater runtime.ObjectCreater, typer runtime.ObjectTyper) runtime.SerializerInfo {
return runtime.SerializerInfo{ return runtime.SerializerInfo{

View File

@ -31,15 +31,3 @@ var (
// Top-level commands/options setup that needs to modify this feature gate should use DefaultMutableFeatureGate. // Top-level commands/options setup that needs to modify this feature gate should use DefaultMutableFeatureGate.
DefaultFeatureGate featuregate.FeatureGate = DefaultMutableFeatureGate DefaultFeatureGate featuregate.FeatureGate = DefaultMutableFeatureGate
) )
var (
// TestOnlyMutableFeatureGate is a mutable version of TestOnlyFeatureGate. Only top-level
// commands/options setup and the k8s.io/component-base/featuregate/testing package should
// make use of this.
TestOnlyMutableFeatureGate featuregate.MutableVersionedFeatureGate = featuregate.NewFeatureGate()
// TestOnlyFeatureGate is a shared global FeatureGate for features that have not yet
// graduated to alpha and require programmatic feature enablement for pre-alpha integration
// testing without exposing the feature as a runtime option.
TestOnlyFeatureGate featuregate.FeatureGate = TestOnlyMutableFeatureGate
)