Wire test-only feature gate for CBOR serving.
To mitigate the risk of introducing a new protocol, integration tests for CBOR will be written using a test-only feature gate instance that is not wired to runtime options. On alpha graduation, the test-only feature gate instance will be replaced by a normal feature gate in the existing apiserver feature gate instance. Kubernetes-commit: 0cad1a89b6721308746cc1a12f12de31a259a0d3
This commit is contained in:
		
							parent
							
								
									781f771b86
								
							
						
					
					
						commit
						f27bb5491e
					
				|  | @ -87,6 +87,15 @@ const ( | ||||||
| 	// Allows authorization to use field and label selectors.
 | 	// Allows authorization to use field and label selectors.
 | ||||||
| 	AuthorizeWithSelectors featuregate.Feature = "AuthorizeWithSelectors" | 	AuthorizeWithSelectors featuregate.Feature = "AuthorizeWithSelectors" | ||||||
| 
 | 
 | ||||||
|  | 	// owner: @benluddy
 | ||||||
|  | 	// kep: https://kep.k8s.io/4222
 | ||||||
|  | 	//
 | ||||||
|  | 	// Enables CBOR as a supported encoding for requests and responses, and as the
 | ||||||
|  | 	// preferred storage encoding for custom resources.
 | ||||||
|  | 	//
 | ||||||
|  | 	// This feature is currently PRE-ALPHA and MUST NOT be enabled outside of integration tests.
 | ||||||
|  | 	TestOnlyCBORServingAndStorage featuregate.Feature = "TestOnlyCBORServingAndStorage" | ||||||
|  | 
 | ||||||
| 	// owner: @serathius
 | 	// owner: @serathius
 | ||||||
| 	// Enables concurrent watch object decoding to avoid starving watch cache when conversion webhook is installed.
 | 	// Enables concurrent watch object decoding to avoid starving watch cache when conversion webhook is installed.
 | ||||||
| 	ConcurrentWatchObjectDecode featuregate.Feature = "ConcurrentWatchObjectDecode" | 	ConcurrentWatchObjectDecode featuregate.Feature = "ConcurrentWatchObjectDecode" | ||||||
|  | @ -238,6 +247,7 @@ 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.
 | ||||||
|  | @ -410,3 +420,12 @@ 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}, | ||||||
|  | 	}, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -742,7 +742,7 @@ func (c *RecommendedConfig) Complete() CompletedConfig { | ||||||
| 	return c.Config.Complete(c.SharedInformerFactory) | 	return c.Config.Complete(c.SharedInformerFactory) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| var allowedMediaTypes = []string{ | var defaultAllowedMediaTypes = []string{ | ||||||
| 	runtime.ContentTypeJSON, | 	runtime.ContentTypeJSON, | ||||||
| 	runtime.ContentTypeYAML, | 	runtime.ContentTypeYAML, | ||||||
| 	runtime.ContentTypeProtobuf, | 	runtime.ContentTypeProtobuf, | ||||||
|  | @ -755,6 +755,10 @@ func (c completedConfig) New(name string, delegationTarget DelegationTarget) (*G | ||||||
| 	if c.Serializer == nil { | 	if c.Serializer == nil { | ||||||
| 		return nil, fmt.Errorf("Genericapiserver.New() called with config.Serializer == nil") | 		return nil, fmt.Errorf("Genericapiserver.New() called with config.Serializer == nil") | ||||||
| 	} | 	} | ||||||
|  | 	allowedMediaTypes := defaultAllowedMediaTypes | ||||||
|  | 	if utilfeature.TestOnlyFeatureGate.Enabled(genericfeatures.TestOnlyCBORServingAndStorage) { | ||||||
|  | 		allowedMediaTypes = append(allowedMediaTypes, runtime.ContentTypeCBOR) | ||||||
|  | 	} | ||||||
| 	for _, info := range c.Serializer.SupportedMediaTypes() { | 	for _, info := range c.Serializer.SupportedMediaTypes() { | ||||||
| 		var ok bool | 		var ok bool | ||||||
| 		for _, mt := range allowedMediaTypes { | 		for _, mt := range allowedMediaTypes { | ||||||
|  |  | ||||||
|  | @ -29,6 +29,7 @@ import ( | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"k8s.io/apimachinery/pkg/runtime" | 	"k8s.io/apimachinery/pkg/runtime" | ||||||
|  | 	"k8s.io/apimachinery/pkg/runtime/serializer" | ||||||
| 	"k8s.io/apimachinery/pkg/util/json" | 	"k8s.io/apimachinery/pkg/util/json" | ||||||
| 	"k8s.io/apimachinery/pkg/util/sets" | 	"k8s.io/apimachinery/pkg/util/sets" | ||||||
| 	"k8s.io/apimachinery/pkg/util/wait" | 	"k8s.io/apimachinery/pkg/util/wait" | ||||||
|  | @ -40,12 +41,14 @@ import ( | ||||||
| 	"k8s.io/apiserver/pkg/authentication/user" | 	"k8s.io/apiserver/pkg/authentication/user" | ||||||
| 	"k8s.io/apiserver/pkg/authorization/authorizer" | 	"k8s.io/apiserver/pkg/authorization/authorizer" | ||||||
| 	"k8s.io/apiserver/pkg/endpoints/request" | 	"k8s.io/apiserver/pkg/endpoints/request" | ||||||
|  | 	"k8s.io/apiserver/pkg/features" | ||||||
| 	"k8s.io/apiserver/pkg/server/healthz" | 	"k8s.io/apiserver/pkg/server/healthz" | ||||||
| 	utilfeature "k8s.io/apiserver/pkg/util/feature" | 	utilfeature "k8s.io/apiserver/pkg/util/feature" | ||||||
| 	utilversion "k8s.io/apiserver/pkg/util/version" | 	utilversion "k8s.io/apiserver/pkg/util/version" | ||||||
| 	"k8s.io/client-go/informers" | 	"k8s.io/client-go/informers" | ||||||
| 	"k8s.io/client-go/kubernetes/fake" | 	"k8s.io/client-go/kubernetes/fake" | ||||||
| 	"k8s.io/client-go/rest" | 	"k8s.io/client-go/rest" | ||||||
|  | 	featuregatetesting "k8s.io/component-base/featuregate/testing" | ||||||
| 	"k8s.io/component-base/tracing" | 	"k8s.io/component-base/tracing" | ||||||
| 	"k8s.io/klog/v2/ktesting" | 	"k8s.io/klog/v2/ktesting" | ||||||
| 	netutils "k8s.io/utils/net" | 	netutils "k8s.io/utils/net" | ||||||
|  | @ -419,3 +422,22 @@ func TestNewErrorForbiddenSerializer(t *testing.T) { | ||||||
| 		t.Errorf("unexpected error: %v", err) | 		t.Errorf("unexpected error: %v", err) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestNewFeatureGatedSerializer(t *testing.T) { | ||||||
|  | 	featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.TestOnlyFeatureGate, features.TestOnlyCBORServingAndStorage, true) | ||||||
|  | 
 | ||||||
|  | 	config := NewConfig(serializer.NewCodecFactory(scheme, serializer.WithSerializer(func(creater runtime.ObjectCreater, typer runtime.ObjectTyper) runtime.SerializerInfo { | ||||||
|  | 		return runtime.SerializerInfo{ | ||||||
|  | 			MediaType:        "application/cbor", | ||||||
|  | 			MediaTypeType:    "application", | ||||||
|  | 			MediaTypeSubType: "cbor", | ||||||
|  | 		} | ||||||
|  | 	}))) | ||||||
|  | 	config.ExternalAddress = "192.168.10.4:443" | ||||||
|  | 	config.EffectiveVersion = utilversion.NewEffectiveVersion("") | ||||||
|  | 	config.LoopbackClientConfig = &rest.Config{} | ||||||
|  | 
 | ||||||
|  | 	if _, err := config.Complete(nil).New("test", NewEmptyDelegate()); err != nil { | ||||||
|  | 		t.Errorf("unexpected error: %v", err) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -31,3 +31,15 @@ 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 | ||||||
|  | ) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue