Merge pull request #138907 from Jefftree/remove-locked-apimachinery-feature-gates

Remove locked GA feature gates (sig-api-machinery)
This commit is contained in:
Kubernetes Prow Robot 2026-05-09 01:57:18 +05:30 committed by GitHub
commit 692d9f21dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 214 additions and 1129 deletions

View file

@ -32,11 +32,9 @@ import (
utilerrors "k8s.io/apimachinery/pkg/util/errors"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/sets"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/discovery"
v1clientset "k8s.io/client-go/kubernetes/typed/core/v1"
"k8s.io/client-go/metadata"
"k8s.io/kubernetes/pkg/features"
)
// NamespacedResourcesDeleterInterface is the interface to delete a namespace with all resources in it.
@ -530,7 +528,7 @@ func (d *namespacedResourcesDeleter) deleteAllContent(ctx context.Context, ns *v
}
podsGVR := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
if _, hasPods := groupVersionResources[podsGVR]; hasPods && utilfeature.DefaultFeatureGate.Enabled(features.OrderedNamespaceDeletion) {
if _, hasPods := groupVersionResources[podsGVR]; hasPods {
// Ensure all pods in the namespace are deleted first
gvrDeletionMetadata, err := d.deleteAllContentForGroupVersionResource(ctx, podsGVR, namespace, namespaceDeletedAt)
if err != nil {
@ -564,7 +562,7 @@ func (d *namespacedResourcesDeleter) deleteAllContent(ctx context.Context, ns *v
// Proceed with deleting other resources in the namespace
for gvr := range groupVersionResources {
if utilfeature.DefaultFeatureGate.Enabled(features.OrderedNamespaceDeletion) && gvr.Group == podsGVR.Group &&
if gvr.Group == podsGVR.Group &&
gvr.Version == podsGVR.Version && gvr.Resource == podsGVR.Resource {
continue
}

View file

@ -23,8 +23,6 @@ import (
"net/http"
"time"
noopoteltrace "go.opentelemetry.io/otel/trace/noop"
"k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/runtime"
utilnet "k8s.io/apimachinery/pkg/util/net"
@ -168,10 +166,8 @@ func BuildGenericConfig(
if lastErr = s.EgressSelector.ApplyTo(genericConfig); lastErr != nil {
return
}
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerTracing) {
if lastErr = s.Traces.ApplyTo(genericConfig.EgressSelector, genericConfig); lastErr != nil {
return
}
if lastErr = s.Traces.ApplyTo(genericConfig.EgressSelector, genericConfig); lastErr != nil {
return
}
// wrap the definitions to revert any changes from disabled features
getOpenAPIDefinitions = openapi.GetOpenAPIDefinitionsWithoutDisabledFeatures(getOpenAPIDefinitions)
@ -189,11 +185,7 @@ func BuildGenericConfig(
if genericConfig.EgressSelector != nil {
s.Etcd.StorageConfig.Transport.EgressLookup = genericConfig.EgressSelector.Lookup
}
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerTracing) {
s.Etcd.StorageConfig.Transport.TracerProvider = genericConfig.TracerProvider
} else {
s.Etcd.StorageConfig.Transport.TracerProvider = noopoteltrace.NewTracerProvider()
}
s.Etcd.StorageConfig.Transport.TracerProvider = genericConfig.TracerProvider
storageFactoryConfig := kubeapiserver.NewStorageFactoryConfigEffectiveVersion(genericConfig.EffectiveVersion)
storageFactoryConfig.APIResourceConfig = genericConfig.MergedResourceConfig

View file

@ -692,12 +692,6 @@ const (
// Enables opportunistic batching in the scheduler.
OpportunisticBatching featuregate.Feature = "OpportunisticBatching"
// owner: @cici37
// kep: https://kep.k8s.io/5080
//
// Enables ordered namespace deletion.
OrderedNamespaceDeletion featuregate.Feature = "OrderedNamespaceDeletion"
// owner: @tallclair
//
// Enables relisting individual pods on-demand.
@ -1043,14 +1037,6 @@ const (
// Enables support for the StorageVersionMigrator controller.
StorageVersionMigrator featuregate.Feature = "StorageVersionMigrator"
// owner: @serathius
// Allow API server JSON encoder to encode collections item by item, instead of all at once.
StreamingCollectionEncodingToJSON featuregate.Feature = "StreamingCollectionEncodingToJSON"
// owner: serathius
// Allow API server Protobuf encoder to encode collections item by item, instead of all at once.
StreamingCollectionEncodingToProtobuf featuregate.Feature = "StreamingCollectionEncodingToProtobuf"
// owner: @danwinship
// kep: https://kep.k8s.io/4858
//
@ -1675,12 +1661,6 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.35"), Default: true, PreRelease: featuregate.Beta},
},
OrderedNamespaceDeletion: {
{Version: version.MustParse("1.30"), Default: false, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.33"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.37
},
PLEGOnDemandRelist: {
{Version: version.MustParse("1.36"), Default: true, PreRelease: featuregate.Beta},
},
@ -1950,16 +1930,6 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.35"), Default: false, PreRelease: featuregate.Beta},
},
StreamingCollectionEncodingToJSON: {
{Version: version.MustParse("1.33"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
},
StreamingCollectionEncodingToProtobuf: {
{Version: version.MustParse("1.33"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
},
StrictIPCIDRValidation: {
{Version: version.MustParse("1.33"), Default: false, PreRelease: featuregate.Alpha},
{Version: version.MustParse("1.36"), Default: true, PreRelease: featuregate.Beta},
@ -2087,12 +2057,6 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.26"), Default: true, PreRelease: featuregate.Beta},
},
genericfeatures.APIServerTracing: {
{Version: version.MustParse("1.22"), Default: false, PreRelease: featuregate.Alpha},
{Version: version.MustParse("1.27"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.37
},
genericfeatures.APIServingWithRoutine: {
{Version: version.MustParse("1.30"), Default: false, PreRelease: featuregate.Alpha},
},
@ -2111,11 +2075,6 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.32"), Default: false, PreRelease: featuregate.Alpha},
},
genericfeatures.BtreeWatchCache: {
{Version: version.MustParse("1.32"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.33"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
},
genericfeatures.CBORServingAndStorage: {
{Version: version.MustParse("1.32"), Default: false, PreRelease: featuregate.Alpha},
},
@ -2124,12 +2083,6 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.31"), Default: false, PreRelease: featuregate.Beta},
},
genericfeatures.ConsistentListFromCache: {
{Version: version.MustParse("1.28"), Default: false, PreRelease: featuregate.Alpha},
{Version: version.MustParse("1.31"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
},
genericfeatures.ConsistentListFromCacheSkipTimeoutFallback: {
{Version: version.MustParse("1.37"), Default: false, PreRelease: featuregate.Alpha},
},
@ -2193,17 +2146,6 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.33"), Default: true, PreRelease: featuregate.Beta},
},
genericfeatures.ResilientWatchCacheInitialization: {
{Version: version.MustParse("1.31"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
},
genericfeatures.RetryGenerateName: {
{Version: version.MustParse("1.30"), Default: false, PreRelease: featuregate.Alpha},
{Version: version.MustParse("1.31"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.32"), Default: true, LockToDefault: true, PreRelease: featuregate.GA},
},
genericfeatures.SeparateCacheWatchRPC: {
{Version: version.MustParse("1.28"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.33"), Default: false, PreRelease: featuregate.Deprecated},
@ -2480,8 +2422,6 @@ var defaultKubernetesFeatureGateDependencies = map[featuregate.Feature][]feature
OpportunisticBatching: {},
OrderedNamespaceDeletion: {},
PLEGOnDemandRelist: {},
PersistentVolumeClaimUnusedSinceTime: {},
@ -2592,10 +2532,6 @@ var defaultKubernetesFeatureGateDependencies = map[featuregate.Feature][]feature
StorageVersionMigrator: {},
StreamingCollectionEncodingToJSON: {},
StreamingCollectionEncodingToProtobuf: {},
StrictIPCIDRValidation: {},
SupplementalGroupsPolicy: {},
@ -2646,8 +2582,6 @@ var defaultKubernetesFeatureGateDependencies = map[featuregate.Feature][]feature
genericfeatures.APIServerIdentity: {},
genericfeatures.APIServerTracing: {},
genericfeatures.APIServingWithRoutine: {},
genericfeatures.AggregatedDiscoveryRemoveBetaType: {},
@ -2656,15 +2590,11 @@ var defaultKubernetesFeatureGateDependencies = map[featuregate.Feature][]feature
genericfeatures.AllowUnsafeMalformedObjectDeletion: {},
genericfeatures.BtreeWatchCache: {},
genericfeatures.CBORServingAndStorage: {},
genericfeatures.ConcurrentWatchObjectDecode: {},
genericfeatures.ConsistentListFromCache: {},
genericfeatures.ConsistentListFromCacheSkipTimeoutFallback: {genericfeatures.ConsistentListFromCache},
genericfeatures.ConsistentListFromCacheSkipTimeoutFallback: {},
genericfeatures.ConstrainedImpersonation: {},
@ -2687,10 +2617,6 @@ var defaultKubernetesFeatureGateDependencies = map[featuregate.Feature][]feature
genericfeatures.RemoteRequestHeaderUID: {},
genericfeatures.ResilientWatchCacheInitialization: {},
genericfeatures.RetryGenerateName: {},
genericfeatures.SeparateCacheWatchRPC: {},
genericfeatures.ShardedListAndWatch: {},

View file

@ -40,7 +40,6 @@ import (
utilnet "k8s.io/apimachinery/pkg/util/net"
utilvalidation "k8s.io/apimachinery/pkg/util/validation"
"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"
@ -452,15 +451,11 @@ func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) {
// MatchPod returns a generic matcher for a given label and field selector.
func MatchPod(label labels.Selector, field fields.Selector) storage.SelectionPredicate {
var indexFields = []string{"spec.nodeName"}
if utilfeature.DefaultFeatureGate.Enabled(features.StorageNamespaceIndex) && !utilfeature.DefaultFeatureGate.Enabled(apiserverfeatures.BtreeWatchCache) {
indexFields = append(indexFields, "metadata.namespace")
}
return storage.SelectionPredicate{
Label: label,
Field: field,
GetAttrs: GetAttrs,
IndexFields: indexFields,
IndexFields: []string{"spec.nodeName"},
}
}
@ -478,24 +473,11 @@ func NodeNameIndexFunc(obj interface{}) ([]string, error) {
return []string{pod.Spec.NodeName}, nil
}
// NamespaceIndexFunc return value name of given object.
func NamespaceIndexFunc(obj interface{}) ([]string, error) {
pod, ok := obj.(*api.Pod)
if !ok {
return nil, fmt.Errorf("not a pod")
}
return []string{pod.Namespace}, nil
}
// Indexers returns the indexers for pod storage.
func Indexers() *cache.Indexers {
var indexers = cache.Indexers{
return &cache.Indexers{
storage.FieldIndex("spec.nodeName"): NodeNameIndexFunc,
}
if utilfeature.DefaultFeatureGate.Enabled(features.StorageNamespaceIndex) && !utilfeature.DefaultFeatureGate.Enabled(apiserverfeatures.BtreeWatchCache) {
indexers[storage.FieldIndex("metadata.namespace")] = NamespaceIndexFunc
}
return &indexers
}
// ToSelectableFields returns a field set that represents the object

View file

@ -73,16 +73,13 @@ func (c *GenericConfig) NewRESTStorage(apiResourceConfigSource serverstorage.API
ParameterCodec: legacyscheme.ParameterCodec,
NegotiatedSerializer: legacyscheme.Codecs,
}
opts := []serializer.CodecFactoryOptionsMutator{}
opts := []serializer.CodecFactoryOptionsMutator{
serializer.WithStreamingCollectionEncodingToJSON(),
serializer.WithStreamingCollectionEncodingToProtobuf(),
}
if utilfeature.DefaultFeatureGate.Enabled(features.CBORServingAndStorage) {
opts = append(opts, serializer.WithSerializer(cbor.NewSerializerInfo))
}
if utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToJSON) {
opts = append(opts, serializer.WithStreamingCollectionEncodingToJSON())
}
if utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToProtobuf) {
opts = append(opts, serializer.WithStreamingCollectionEncodingToProtobuf())
}
if len(opts) != 0 {
apiGroupInfo.NegotiatedSerializer = serializer.NewCodecFactory(legacyscheme.Scheme, opts...)
}

View file

@ -888,7 +888,6 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
clusterScoped := crd.Spec.Scope == apiextensionsv1.ClusterScoped
// CRDs explicitly do not support protobuf, but some objects returned by the API server do
streamingCollections := utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToJSON)
negotiatedSerializer := unstructuredNegotiatedSerializer{
typer: typer,
creator: creator,
@ -902,11 +901,11 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
MediaTypeType: "application",
MediaTypeSubType: "json",
EncodesAsText: true,
Serializer: json.NewSerializerWithOptions(json.DefaultMetaFactory, creator, typer, json.SerializerOptions{StreamingCollectionsEncoding: streamingCollections}),
Serializer: json.NewSerializerWithOptions(json.DefaultMetaFactory, creator, typer, json.SerializerOptions{StreamingCollectionsEncoding: true}),
PrettySerializer: json.NewSerializerWithOptions(json.DefaultMetaFactory, creator, typer, json.SerializerOptions{Pretty: true}),
StrictSerializer: json.NewSerializerWithOptions(json.DefaultMetaFactory, creator, typer, json.SerializerOptions{
Strict: true,
StreamingCollectionsEncoding: streamingCollections,
StreamingCollectionsEncoding: true,
}),
StreamSerializer: &runtime.StreamSerializerInfo{
EncodesAsText: true,
@ -930,7 +929,7 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
MediaTypeType: "application",
MediaTypeSubType: "vnd.kubernetes.protobuf",
Serializer: protobuf.NewSerializerWithOptions(creator, typer, protobuf.SerializerOptions{
StreamingCollectionsEncoding: utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToProtobuf),
StreamingCollectionsEncoding: true,
}),
StreamSerializer: &runtime.StreamSerializerInfo{
Serializer: protobuf.NewRawSerializer(creator, typer),
@ -1007,16 +1006,13 @@ func (r *crdHandler) getOrCreateServingInfoFor(uid types.UID, name string) (*crd
scaleScope := *requestScopes[v.Name]
scaleConverter := scale.NewScaleConverter()
scaleScope.Subresource = "scale"
var opts []serializer.CodecFactoryOptionsMutator
opts := []serializer.CodecFactoryOptionsMutator{
serializer.WithStreamingCollectionEncodingToJSON(),
serializer.WithStreamingCollectionEncodingToProtobuf(),
}
if utilfeature.DefaultFeatureGate.Enabled(features.CBORServingAndStorage) {
opts = append(opts, serializer.WithSerializer(cbor.NewSerializerInfo))
}
if utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToJSON) {
opts = append(opts, serializer.WithStreamingCollectionEncodingToJSON())
}
if utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToProtobuf) {
opts = append(opts, serializer.WithStreamingCollectionEncodingToProtobuf())
}
scaleScope.Serializer = serializer.NewCodecFactory(scaleConverter.Scheme(), opts...)
scaleScope.Kind = autoscalingv1.SchemeGroupVersion.WithKind("Scale")
scaleScope.Namer = handlers.ContextBasedNaming{

View file

@ -44,11 +44,6 @@ const (
// Assigns each kube-apiserver an ID in a cluster.
APIServerIdentity featuregate.Feature = "APIServerIdentity"
// owner: @dashpole
//
// Add support for distributed tracing in the API Server
APIServerTracing featuregate.Feature = "APIServerTracing"
// owner: @linxiulei
//
// Enables serving watch requests in separate goroutines.
@ -75,11 +70,6 @@ const (
// resources using the Kubernetes API only.
AllowUnsafeMalformedObjectDeletion featuregate.Feature = "AllowUnsafeMalformedObjectDeletion"
// owner: @serathius
//
// Replaces watch cache hashmap implementation with a btree based one, bringing performance improvements.
BtreeWatchCache featuregate.Feature = "BtreeWatchCache"
// owner: @benluddy
// kep: https://kep.k8s.io/4222
//
@ -91,12 +81,6 @@ const (
// Enables concurrent watch object decoding to avoid starving watch cache when conversion webhook is installed.
ConcurrentWatchObjectDecode featuregate.Feature = "ConcurrentWatchObjectDecode"
// owner: @serathius
// kep: http://kep.k8s.io/2340
//
// Allow the API server to serve consistent lists from cache
ConsistentListFromCache featuregate.Feature = "ConsistentListFromCache"
// owner: @yedou37
//
// Skip the timeout fallback to storage when a consistent LIST from cache cannot be served,
@ -205,17 +189,6 @@ const (
// headers when forwarding requests to the servers serving the aggregated API.
RemoteRequestHeaderUID featuregate.Feature = "RemoteRequestHeaderUID"
// owner: @wojtek-t
//
// Enables resilient watchcache initialization to avoid controlplane
// overload.
ResilientWatchCacheInitialization featuregate.Feature = "ResilientWatchCacheInitialization"
// owner: @jpbetz
// Resource create requests using generateName are retried automatically by the apiserver
// if the generated name conflicts with an existing resource name, up to a maximum number of 7 retries.
RetryGenerateName featuregate.Feature = "RetryGenerateName"
// owner: @cici37
//
// Allow watch cache to create a watch on a dedicated RPC.
@ -246,14 +219,6 @@ const (
// document.
StorageVersionHash featuregate.Feature = "StorageVersionHash"
// owner: @serathius
// Allow API server JSON encoder to encode collections item by item, instead of all at once.
StreamingCollectionEncodingToJSON featuregate.Feature = "StreamingCollectionEncodingToJSON"
// owner: @serathius
// Allow API server Protobuf encoder to encode collections item by item, instead of all at once.
StreamingCollectionEncodingToProtobuf featuregate.Feature = "StreamingCollectionEncodingToProtobuf"
// owner: @aramase, @enj, @nabokihms
// kep: https://kep.k8s.io/3331
//
@ -331,12 +296,6 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.26"), Default: true, PreRelease: featuregate.Beta},
},
APIServerTracing: {
{Version: version.MustParse("1.22"), Default: false, PreRelease: featuregate.Alpha},
{Version: version.MustParse("1.27"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.37
},
APIServingWithRoutine: {
{Version: version.MustParse("1.30"), Default: false, PreRelease: featuregate.Alpha},
},
@ -355,11 +314,6 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.32"), Default: false, PreRelease: featuregate.Alpha},
},
BtreeWatchCache: {
{Version: version.MustParse("1.32"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.33"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
},
CBORServingAndStorage: {
{Version: version.MustParse("1.32"), Default: false, PreRelease: featuregate.Alpha},
},
@ -368,12 +322,6 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.31"), Default: false, PreRelease: featuregate.Beta},
},
ConsistentListFromCache: {
{Version: version.MustParse("1.28"), Default: false, PreRelease: featuregate.Alpha},
{Version: version.MustParse("1.31"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
},
ConsistentListFromCacheSkipTimeoutFallback: {
{Version: version.MustParse("1.37"), Default: false, PreRelease: featuregate.Alpha},
},
@ -437,17 +385,6 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.33"), Default: true, PreRelease: featuregate.Beta},
},
ResilientWatchCacheInitialization: {
{Version: version.MustParse("1.31"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
},
RetryGenerateName: {
{Version: version.MustParse("1.30"), Default: false, PreRelease: featuregate.Alpha},
{Version: version.MustParse("1.31"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.32"), Default: true, LockToDefault: true, PreRelease: featuregate.GA},
},
SeparateCacheWatchRPC: {
{Version: version.MustParse("1.28"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.33"), Default: false, PreRelease: featuregate.Deprecated},
@ -471,16 +408,6 @@ var defaultVersionedKubernetesFeatureGates = map[featuregate.Feature]featuregate
{Version: version.MustParse("1.15"), Default: true, PreRelease: featuregate.Beta},
},
StreamingCollectionEncodingToJSON: {
{Version: version.MustParse("1.33"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
},
StreamingCollectionEncodingToProtobuf: {
{Version: version.MustParse("1.33"), Default: true, PreRelease: featuregate.Beta},
{Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.GA, LockToDefault: true},
},
StructuredAuthenticationConfigurationEgressSelector: {
{Version: version.MustParse("1.34"), Default: true, PreRelease: featuregate.Beta},
},

View file

@ -452,7 +452,7 @@ const maxNameGenerationCreateAttempts = 8
// hooks). Tests which call this might want to call DeepCopy if they expect to
// be able to examine the input and output objects for differences.
func (e *Store) Create(ctx context.Context, obj runtime.Object, createValidation rest.ValidateObjectFunc, options *metav1.CreateOptions) (runtime.Object, error) {
if utilfeature.DefaultFeatureGate.Enabled(features.RetryGenerateName) && needsNameGeneration(obj) {
if needsNameGeneration(obj) {
return e.createWithGenerateNameRetry(ctx, obj, createValidation, options)
}

View file

@ -45,12 +45,10 @@ import (
"k8s.io/apimachinery/pkg/selection"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/validation/field"
"k8s.io/apimachinery/pkg/util/version"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/apis/example"
examplev1 "k8s.io/apiserver/pkg/apis/example/v1"
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/features"
"k8s.io/apiserver/pkg/registry/generic"
"k8s.io/apiserver/pkg/registry/rest"
"k8s.io/apiserver/pkg/storage"
@ -59,9 +57,7 @@ import (
"k8s.io/apiserver/pkg/storage/names"
"k8s.io/apiserver/pkg/storage/storagebackend/factory"
storagetesting "k8s.io/apiserver/pkg/storage/testing"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/tools/cache"
featuregatetesting "k8s.io/component-base/featuregate/testing"
)
var scheme = runtime.NewScheme()
@ -451,38 +447,6 @@ func TestStoreCreateWithRetryNameGenerate(t *testing.T) {
}
}
func TestStoreCreateWithRetryNameGenerateFeatureDisabled(t *testing.T) {
// Preserve testing of disabled RetryGenerateName feature gate since it can still be disabled when emulation version is set.
featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.31"))
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.RetryGenerateName, false)
namedObj := func(id int) *example.Pod {
return &example.Pod{
ObjectMeta: metav1.ObjectMeta{Name: fmt.Sprintf("prefix-%d", id), Namespace: "test"},
Spec: example.PodSpec{NodeName: "machine"},
}
}
generateNameObj := &example.Pod{
ObjectMeta: metav1.ObjectMeta{GenerateName: "prefix-", Namespace: "test"},
Spec: example.PodSpec{NodeName: "machine"},
}
testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test")
destroyFunc, registry := NewTestGenericStoreRegistry(t)
defer destroyFunc()
registry.CreateStrategy = &testRESTStrategy{scheme, &sequentialNameGenerator{}, true, false, true}
_, err := registry.Create(testContext, namedObj(0), rest.ValidateAllObjectFunc, &metav1.CreateOptions{})
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
_, err = registry.Create(testContext, generateNameObj, rest.ValidateAllObjectFunc, &metav1.CreateOptions{})
if err == nil || !errors.IsAlreadyExists(err) {
t.Error("Expected already exists error")
}
}
func TestNewCreateOptionsFromUpdateOptions(t *testing.T) {
f := randfill.New().NilChance(0.0).NumElements(1, 1)
@ -2464,13 +2428,11 @@ func newTestGenericStoreRegistry(t *testing.T, scheme *runtime.Scheme, hasCacheE
if err != nil {
t.Fatalf("Couldn't create cacher: %v", err)
}
if utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
// The tests assume that Get/GetList/Watch calls shouldn't fail.
// However, 429 error can now be returned if watchcache is under initialization.
// To avoid rewriting all tests, we wait for watchcache to initialize.
if err := cacher.Wait(context.Background()); err != nil {
t.Fatal(err)
}
// The tests assume that Get/GetList/Watch calls shouldn't fail.
// However, 429 error can now be returned if watchcache is under initialization.
// To avoid rewriting all tests, we wait for watchcache to initialize.
if err := cacher.Wait(context.Background()); err != nil {
t.Fatal(err)
}
d := destroyFunc
delegator := cacherstorage.NewCacheDelegator(cacher, s)
@ -2990,76 +2952,3 @@ func TestValidateIndexers(t *testing.T) {
}
}
}
type predictableNameGenerator struct {
index int
}
func (p *predictableNameGenerator) GenerateName(base string) string {
p.index++
return fmt.Sprintf("%s%d", base, p.index)
}
func TestStoreCreateGenerateNameConflict(t *testing.T) {
// Preserve testing of disabled RetryGenerateName feature gate since it can still be disabled when emulation version is set.
featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.31"))
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.RetryGenerateName, false)
// podA will be stored with name foo12345
podA := &example.Pod{
ObjectMeta: metav1.ObjectMeta{Name: "foo1", Namespace: "test"},
Spec: example.PodSpec{NodeName: "machine"},
}
// podB will generate the same name as podA "foo1" in the first try
podB := &example.Pod{
ObjectMeta: metav1.ObjectMeta{GenerateName: "foo", Namespace: "test"},
Spec: example.PodSpec{NodeName: "machine2"},
}
testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test")
destroyFunc, registry := NewTestGenericStoreRegistry(t)
defer destroyFunc()
// re-define delete strategy to have graceful delete capability
defaultCreateStrategy := &testRESTStrategy{scheme, &predictableNameGenerator{}, true, false, true}
registry.CreateStrategy = defaultCreateStrategy
// create the object (DeepCopy because the registry mutates the objects)
objA, err := registry.Create(testContext, podA.DeepCopy(), rest.ValidateAllObjectFunc, &metav1.CreateOptions{})
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
// get the object
checkobjA, err := registry.Get(testContext, podA.Name, &metav1.GetOptions{})
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
// verify objects are equal
if e, a := objA, checkobjA; !reflect.DeepEqual(e, a) {
t.Errorf("Expected %#v, got %#v", e, a)
}
// now try to create the second pod (DeepCopy because the registry mutate the objects)
_, err = registry.Create(testContext, podB.DeepCopy(), rest.ValidateAllObjectFunc, &metav1.CreateOptions{})
if !errors.IsAlreadyExists(err) {
t.Errorf("Unexpected error: %+v", err)
}
// check the 'alraedy exists' msg correspond to the generated name
msg := &err.(*errors.StatusError).ErrStatus.Message
if !strings.Contains(*msg, "already exists, the server was not able to generate a unique name for the object") {
t.Errorf("Unexpected error without the 'was not able to generate a unique name' in message: %v", err)
}
// now try to create the second pod again
objB, err := registry.Create(testContext, podB.DeepCopy(), rest.ValidateAllObjectFunc, &metav1.CreateOptions{})
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
if objB.(*example.Pod).Name != "foo2" && objB.(*example.Pod).GenerateName != "foo" {
t.Errorf("Unexpected object: %+v", objB)
}
}

View file

@ -1069,9 +1069,7 @@ func DefaultBuildHandlerChain(apiHandler http.Handler, c *Config) http.Handler {
// WithTracing comes after authentication so we can allow authenticated
// clients to influence sampling.
if c.FeatureGate.Enabled(genericfeatures.APIServerTracing) {
handler = genericapifilters.WithTracing(handler, c.TracerProvider)
}
handler = genericapifilters.WithTracing(handler, c.TracerProvider)
failedHandler = filterlatency.TrackCompleted(failedHandler)
handler = filterlatency.TrackCompleted(handler)
handler = genericapifilters.WithAuthentication(handler, c.Authentication.Authenticator, failedHandler, c.Authentication.APIAudiences, c.Authentication.RequestHeaderConfig)

View file

@ -1017,16 +1017,13 @@ func (s *GenericAPIServer) newAPIGroupVersion(apiGroupInfo *APIGroupInfo, groupV
// NewDefaultAPIGroupInfo returns an APIGroupInfo stubbed with "normal" values
// exposed for easier composition from other packages
func NewDefaultAPIGroupInfo(group string, scheme *runtime.Scheme, parameterCodec runtime.ParameterCodec, codecs serializer.CodecFactory) APIGroupInfo {
opts := []serializer.CodecFactoryOptionsMutator{}
opts := []serializer.CodecFactoryOptionsMutator{
serializer.WithStreamingCollectionEncodingToJSON(),
serializer.WithStreamingCollectionEncodingToProtobuf(),
}
if utilfeature.DefaultFeatureGate.Enabled(features.CBORServingAndStorage) {
opts = append(opts, serializer.WithSerializer(cbor.NewSerializerInfo))
}
if utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToJSON) {
opts = append(opts, serializer.WithStreamingCollectionEncodingToJSON())
}
if utilfeature.DefaultFeatureGate.Enabled(features.StreamingCollectionEncodingToProtobuf) {
opts = append(opts, serializer.WithStreamingCollectionEncodingToProtobuf())
}
if len(opts) != 0 {
codecs = serializer.NewCodecFactory(scheme, opts...)
}

View file

@ -21,9 +21,7 @@ import (
"time"
"github.com/spf13/pflag"
"k8s.io/apiserver/pkg/features"
"k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/util/feature"
clientgoinformers "k8s.io/client-go/informers"
clientgoclientset "k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
@ -72,9 +70,7 @@ func (o *CoreAPIOptions) ApplyTo(config *server.RecommendedConfig) error {
return err
}
}
if feature.DefaultFeatureGate.Enabled(features.APIServerTracing) {
kubeconfig.Wrap(tracing.WrapperFor(config.TracerProvider))
}
kubeconfig.Wrap(tracing.WrapperFor(config.TracerProvider))
clientgoExternalClient, err := clientgoclientset.NewForConfig(kubeconfig)
if err != nil {
return fmt.Errorf("failed to create Kubernetes clientset: %v", err)

View file

@ -34,7 +34,6 @@ import (
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apiserver/pkg/apis/apiserver"
"k8s.io/apiserver/pkg/apis/apiserver/install"
"k8s.io/apiserver/pkg/features"
"k8s.io/apiserver/pkg/server"
"k8s.io/apiserver/pkg/server/egressselector"
"k8s.io/apiserver/pkg/util/feature"
@ -87,9 +86,6 @@ func (o *TracingOptions) ApplyTo(es *egressselector.EgressSelector, c *server.Co
if o == nil || o.ConfigFile == "" {
return nil
}
if !feature.DefaultFeatureGate.Enabled(features.APIServerTracing) {
return fmt.Errorf("APIServerTracing feature is not enabled, but tracing config file was provided")
}
traceConfig, err := ReadTracingConfiguration(o.ConfigFile)
if err != nil {

View file

@ -521,19 +521,9 @@ func (c *Cacher) Watch(ctx context.Context, key string, opts storage.ListOptions
return nil, err
}
var readyGeneration int
if utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
var err error
var downtime time.Duration
readyGeneration, downtime, err = c.ready.checkAndReadGeneration()
if err != nil {
return nil, errors.NewTooManyRequests(err.Error(), calculateRetryAfterForUnreadyCache(downtime))
}
} else {
readyGeneration, err = c.ready.waitAndReadGeneration(ctx)
if err != nil {
return nil, errors.NewServiceUnavailable(err.Error())
}
readyGeneration, downtime, err := c.ready.checkAndReadGeneration()
if err != nil {
return nil, errors.NewTooManyRequests(err.Error(), calculateRetryAfterForUnreadyCache(downtime))
}
// determine the namespace and name scope of the watch, first from the request, secondarily from the field selector
@ -760,16 +750,10 @@ func (c *Cacher) GetList(ctx context.Context, key string, opts storage.ListOptio
attribute.Stringer("type", c.groupResource))
defer span.End(500 * time.Millisecond)
if utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if downtime, err := c.ready.check(); err != nil {
// If Cacher is not initialized, reject List requests
// as described in https://kep.k8s.io/4568
return errors.NewTooManyRequests(err.Error(), calculateRetryAfterForUnreadyCache(downtime))
}
} else {
if err := c.ready.wait(ctx); err != nil {
return errors.NewServiceUnavailable(err.Error())
}
if downtime, err := c.ready.check(); err != nil {
// If Cacher is not initialized, reject List requests
// as described in https://kep.k8s.io/4568
return errors.NewTooManyRequests(err.Error(), calculateRetryAfterForUnreadyCache(downtime))
}
span.AddEvent("Ready")

View file

@ -32,7 +32,6 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/rand"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
"k8s.io/apimachinery/pkg/util/version"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apiserver/pkg/apis/example"
examplev1 "k8s.io/apiserver/pkg/apis/example/v1"
@ -181,36 +180,30 @@ func TestListPaging(t *testing.T) {
}
func TestLists(t *testing.T) {
for _, consistentRead := range []bool{true, false} {
for _, listFromCacheSnapshot := range []bool{true, false} {
t.Run(fmt.Sprintf("ConsistentListFromCache=%v,ListFromCacheSnapshot=%v", consistentRead, listFromCacheSnapshot), func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ListFromCacheSnapshot, listFromCacheSnapshot)
if !consistentRead {
featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.33"))
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ConsistentListFromCache, false)
}
t.Run("List", func(t *testing.T) {
t.Parallel()
ctx, cacher, server, terminate := testSetupWithEtcdServer(t)
t.Cleanup(terminate)
storagetesting.RunTestList(ctx, t, cacher, compactStore(cacher, server.V3Client.Client), true, server.V3Client.Kubernetes.(*storagetesting.KubernetesRecorder))
})
t.Run("ConsistentList", func(t *testing.T) {
t.Parallel()
ctx, cacher, server, terminate := testSetupWithEtcdServer(t)
t.Cleanup(terminate)
storagetesting.RunTestConsistentList(ctx, t, cacher, increaseRVFunc(server.V3Client.Client), true, consistentRead, listFromCacheSnapshot)
})
t.Run("GetListNonRecursive", func(t *testing.T) {
t.Parallel()
ctx, cacher, server, terminate := testSetupWithEtcdServer(t)
t.Cleanup(terminate)
storagetesting.RunTestGetListNonRecursive(ctx, t, increaseRVFunc(server.V3Client.Client), cacher)
})
for _, listFromCacheSnapshot := range []bool{true, false} {
t.Run(fmt.Sprintf("ListFromCacheSnapshot=%v", listFromCacheSnapshot), func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ListFromCacheSnapshot, listFromCacheSnapshot)
t.Run("List", func(t *testing.T) {
t.Parallel()
ctx, cacher, server, terminate := testSetupWithEtcdServer(t)
t.Cleanup(terminate)
storagetesting.RunTestList(ctx, t, cacher, compactStore(cacher, server.V3Client.Client), true, server.V3Client.Kubernetes.(*storagetesting.KubernetesRecorder))
})
}
t.Run("ConsistentList", func(t *testing.T) {
t.Parallel()
ctx, cacher, server, terminate := testSetupWithEtcdServer(t)
t.Cleanup(terminate)
storagetesting.RunTestConsistentList(ctx, t, cacher, increaseRVFunc(server.V3Client.Client), true, true, listFromCacheSnapshot)
})
t.Run("GetListNonRecursive", func(t *testing.T) {
t.Parallel()
ctx, cacher, server, terminate := testSetupWithEtcdServer(t)
t.Cleanup(terminate)
storagetesting.RunTestGetListNonRecursive(ctx, t, increaseRVFunc(server.V3Client.Client), cacher)
})
})
}
}
@ -592,13 +585,11 @@ func testSetupWithEtcdServer(t testing.TB, opts ...setupOption) (context.Context
t.Fatalf("Failed to inject list errors: %v", err)
}
if utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
// The tests assume that Get/GetList/Watch calls shouldn't fail.
// However, 429 error can now be returned if watchcache is under initialization.
// To avoid rewriting all tests, we wait for watchcache to initialize.
if err := cacher.Wait(ctx); err != nil {
t.Fatal(err)
}
// The tests assume that Get/GetList/Watch calls shouldn't fail.
// However, 429 error can now be returned if watchcache is under initialization.
// To avoid rewriting all tests, we wait for watchcache to initialize.
if err := cacher.Wait(ctx); err != nil {
t.Fatal(err)
}
delegator := NewCacheDelegator(cacher, wrappedStorage)
terminate := func() {
@ -613,11 +604,6 @@ func testSetupWithEtcdServer(t testing.TB, opts ...setupOption) (context.Context
func testSetupWithEtcdAndCreateWrapper(t *testing.T, opts ...setupOption) (storage.Interface, tearDownFunc) {
_, cacher, _, tearDown := testSetupWithEtcdServer(t, opts...)
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.cacher.ready.wait(context.TODO()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
return &createWrapper{CacheDelegator: cacher}, tearDown
}
@ -647,35 +633,17 @@ func (c *createWrapper) Create(ctx context.Context, key string, obj, out runtime
func BenchmarkStoreCreateList(b *testing.B) {
klog.SetLogger(logr.Discard())
storeOptions := []struct {
name string
btreeEnabled bool
}{
{
name: "Btree",
btreeEnabled: true,
},
{
name: "Map",
btreeEnabled: false,
},
}
for _, store := range storeOptions {
b.Run(fmt.Sprintf("Store=%s", store.name), func(b *testing.B) {
featuregatetesting.SetFeatureGateDuringTest(b, utilfeature.DefaultFeatureGate, features.BtreeWatchCache, store.btreeEnabled)
for _, rvm := range []metav1.ResourceVersionMatch{metav1.ResourceVersionMatchNotOlderThan, metav1.ResourceVersionMatchExact} {
b.Run(fmt.Sprintf("RV=%s", rvm), func(b *testing.B) {
for _, useIndex := range []bool{true, false} {
b.Run(fmt.Sprintf("Indexed=%v", useIndex), func(b *testing.B) {
opts := []setupOption{}
if useIndex {
opts = append(opts, withNodeNameAndNamespaceIndex)
}
ctx, cacher, _, terminate := testSetupWithEtcdServer(b, opts...)
b.Cleanup(terminate)
storagetesting.RunBenchmarkStoreListCreate(ctx, b, cacher, rvm)
})
for _, rvm := range []metav1.ResourceVersionMatch{metav1.ResourceVersionMatchNotOlderThan, metav1.ResourceVersionMatchExact} {
b.Run(fmt.Sprintf("RV=%s", rvm), func(b *testing.B) {
for _, useIndex := range []bool{true, false} {
b.Run(fmt.Sprintf("Indexed=%v", useIndex), func(b *testing.B) {
opts := []setupOption{}
if useIndex {
opts = append(opts, withNodeNameAndNamespaceIndex)
}
ctx, cacher, _, terminate := testSetupWithEtcdServer(b, opts...)
b.Cleanup(terminate)
storagetesting.RunBenchmarkStoreListCreate(ctx, b, cacher, rvm)
})
}
})
@ -709,36 +677,18 @@ func BenchmarkStoreList(b *testing.B) {
for _, dims := range dimensions {
b.Run(fmt.Sprintf("Namespaces=%d/Pods=%d/Nodes=%d", dims.namespaceCount, dims.namespaceCount*dims.podPerNamespaceCount, dims.nodeCount), func(b *testing.B) {
data := storagetesting.PrepareBenchchmarkData(dims.namespaceCount, dims.podPerNamespaceCount, dims.nodeCount)
storeOptions := []struct {
name string
btreeEnabled bool
}{
{
name: "Btree",
btreeEnabled: true,
},
{
name: "Map",
btreeEnabled: false,
},
ctx, cacher, _, terminate := testSetupWithEtcdServer(b, withNodeNameAndNamespaceIndex)
b.Cleanup(terminate)
var out example.Pod
for _, pod := range data.Pods {
err := cacher.Create(ctx, computePodKey(pod), pod, &out, 0)
if err != nil {
b.Fatal(err)
}
}
for _, store := range storeOptions {
b.Run(fmt.Sprintf("Store=%s", store.name), func(b *testing.B) {
featuregatetesting.SetFeatureGateDuringTest(b, utilfeature.DefaultFeatureGate, features.BtreeWatchCache, store.btreeEnabled)
ctx, cacher, _, terminate := testSetupWithEtcdServer(b, withNodeNameAndNamespaceIndex)
b.Cleanup(terminate)
var out example.Pod
for _, pod := range data.Pods {
err := cacher.Create(ctx, computePodKey(pod), pod, &out, 0)
if err != nil {
b.Fatal(err)
}
}
for _, useIndex := range []bool{true, false} {
b.Run(fmt.Sprintf("Indexed=%v", useIndex), func(b *testing.B) {
storagetesting.RunBenchmarkStoreList(ctx, b, cacher, data, useIndex)
})
}
for _, useIndex := range []bool{true, false} {
b.Run(fmt.Sprintf("Indexed=%v", useIndex), func(b *testing.B) {
storagetesting.RunBenchmarkStoreList(ctx, b, cacher, data, useIndex)
})
}
})

View file

@ -43,7 +43,6 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/sharding"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/version"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/apiserver/pkg/apis/example"
@ -106,13 +105,11 @@ func newTestCacher(s storage.Interface) (*Cacher, storage.Versioner, error) {
return nil, versioner, err
}
if utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
// The tests assume that Get/GetList/Watch calls shouldn't fail.
// However, 429 error can now be returned if watchcache is under initialization.
// To avoid rewriting all tests, we wait for watcache to initialize.
if err := cacher.Wait(context.Background()); err != nil {
return nil, storage.APIObjectVersioner{}, err
}
// The tests assume that Get/GetList/Watch calls shouldn't fail.
// However, 429 error can now be returned if watchcache is under initialization.
// To avoid rewriting all tests, we wait for watcache to initialize.
if err := cacher.Wait(context.Background()); err != nil {
return nil, storage.APIObjectVersioner{}, err
}
return cacher, versioner, nil
}
@ -296,67 +293,46 @@ func TestShouldDelegateList(t *testing.T) {
snapshotAvailableOverrides[opts{Recursive: true, ResourceVersion: oldRV, ResourceVersionMatch: metav1.ResourceVersionMatchExact}] = false
snapshotAvailableOverrides[opts{Recursive: true, ResourceVersion: oldRV, ResourceVersionMatch: metav1.ResourceVersionMatchExact, Limit: 100}] = false
t.Run("ConsistentListFromCache=false", func(t *testing.T) {
featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.33"))
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ConsistentListFromCache, false)
t.Run("ListFromCacheSnapshot=false", func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ListFromCacheSnapshot, false)
runTestCases(t, false, testCases)
})
// TODO(p0lyn0mial): the following tests assume that etcdfeature.DefaultFeatureSupportChecker.Supports(storage.RequestWatchProgress)
// evaluates to true. Otherwise the cache will be bypassed and the test will fail.
//
// If you were to run only TestGetListCacheBypass you would see that the test fail.
// However in CI all test are run and there must be a test(s) that properly
// initialize the storage layer so that the mentioned method evaluates to true
forceRequestWatchProgressSupport(t)
t.Run("ListFromCacheSnapshot=true", func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ListFromCacheSnapshot, true)
t.Run("SnapshotAvailable=false", func(t *testing.T) {
runTestCases(t, false, testCases, listFromSnapshotEnabledOverrides)
})
t.Run("SnapshotAvailable=true", func(t *testing.T) {
runTestCases(t, true, testCases, listFromSnapshotEnabledOverrides, snapshotAvailableOverrides)
})
})
consistentListFromCacheOverrides := map[opts]bool{}
for _, recursive := range []bool{true, false} {
consistentListFromCacheOverrides[opts{Recursive: recursive}] = false
consistentListFromCacheOverrides[opts{Limit: 100, Recursive: recursive}] = false
}
t.Run("ListFromCacheSnapshot=false", func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ListFromCacheSnapshot, false)
runTestCases(t, false, testCases, consistentListFromCacheOverrides)
})
t.Run("ConsistentListFromCache=true", func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ConsistentListFromCache, true)
// TODO(p0lyn0mial): the following tests assume that etcdfeature.DefaultFeatureSupportChecker.Supports(storage.RequestWatchProgress)
// evaluates to true. Otherwise the cache will be bypassed and the test will fail.
//
// If you were to run only TestGetListCacheBypass you would see that the test fail.
// However in CI all test are run and there must be a test(s) that properly
// initialize the storage layer so that the mentioned method evaluates to true
forceRequestWatchProgressSupport(t)
t.Run("ListFromCacheSnapshot=true", func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ListFromCacheSnapshot, true)
consistentListFromCacheOverrides := map[opts]bool{}
for _, recursive := range []bool{true, false} {
consistentListFromCacheOverrides[opts{Recursive: recursive}] = false
consistentListFromCacheOverrides[opts{Limit: 100, Recursive: recursive}] = false
}
t.Run("ListFromCacheSnapshot=false", func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ListFromCacheSnapshot, false)
runTestCases(t, false, testCases, consistentListFromCacheOverrides)
consistentReadWithSnapshotOverrides := map[opts]bool{}
// Continues with negative RV are same as consistent read.
consistentReadWithSnapshotOverrides[opts{Recursive: true, Limit: 0, Continue: continueOnNegativeRV}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, Limit: 100, Continue: continueOnNegativeRV}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: "0", Limit: 0, Continue: continueOnNegativeRV}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: "0", Limit: 100, Continue: continueOnNegativeRV}] = false
// Exact on RV not yet observed by cache
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: etcdRV, Limit: 100}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: etcdRV, ResourceVersionMatch: metav1.ResourceVersionMatchExact}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: etcdRV, ResourceVersionMatch: metav1.ResourceVersionMatchExact, Limit: 100}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, Continue: continueOnEtcdRV}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: "0", Continue: continueOnEtcdRV}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, Continue: continueOnEtcdRV, Limit: 100}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: "0", Continue: continueOnEtcdRV, Limit: 100}] = false
t.Run("SnapshotAvailable=false", func(t *testing.T) {
runTestCases(t, false, testCases, listFromSnapshotEnabledOverrides, consistentListFromCacheOverrides, consistentReadWithSnapshotOverrides)
})
t.Run("ListFromCacheSnapshot=true", func(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ListFromCacheSnapshot, true)
consistentReadWithSnapshotOverrides := map[opts]bool{}
// Continues with negative RV are same as consistent read.
consistentReadWithSnapshotOverrides[opts{Recursive: true, Limit: 0, Continue: continueOnNegativeRV}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, Limit: 100, Continue: continueOnNegativeRV}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: "0", Limit: 0, Continue: continueOnNegativeRV}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: "0", Limit: 100, Continue: continueOnNegativeRV}] = false
// Exact on RV not yet observed by cache
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: etcdRV, Limit: 100}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: etcdRV, ResourceVersionMatch: metav1.ResourceVersionMatchExact}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: etcdRV, ResourceVersionMatch: metav1.ResourceVersionMatchExact, Limit: 100}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, Continue: continueOnEtcdRV}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: "0", Continue: continueOnEtcdRV}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, Continue: continueOnEtcdRV, Limit: 100}] = false
consistentReadWithSnapshotOverrides[opts{Recursive: true, ResourceVersion: "0", Continue: continueOnEtcdRV, Limit: 100}] = false
t.Run("SnapshotAvailable=false", func(t *testing.T) {
runTestCases(t, false, testCases, listFromSnapshotEnabledOverrides, consistentListFromCacheOverrides, consistentReadWithSnapshotOverrides)
})
t.Run("SnapshotAvailable=true", func(t *testing.T) {
runTestCases(t, true, testCases, listFromSnapshotEnabledOverrides, consistentListFromCacheOverrides, consistentReadWithSnapshotOverrides, snapshotAvailableOverrides)
})
t.Run("SnapshotAvailable=true", func(t *testing.T) {
runTestCases(t, true, testCases, listFromSnapshotEnabledOverrides, consistentListFromCacheOverrides, consistentReadWithSnapshotOverrides, snapshotAvailableOverrides)
})
})
}
@ -371,12 +347,11 @@ func mustAtoi(s string) int {
func TestConsistentReadFallback(t *testing.T) {
tcs := []struct {
name string
consistentReadsEnabled bool
skipStorageFallback bool
watchCacheRV string
storageRV string
fallbackError bool
name string
skipStorageFallback bool
watchCacheRV string
storageRV string
fallbackError bool
expectError bool
expectTooManyRequests bool
@ -387,7 +362,6 @@ func TestConsistentReadFallback(t *testing.T) {
}{
{
name: "Success",
consistentReadsEnabled: true,
watchCacheRV: "42",
storageRV: "42",
expectRV: "42",
@ -400,7 +374,6 @@ apiserver_watch_cache_consistent_read_total{fallback="false", group="", resource
},
{
name: "Fallback",
consistentReadsEnabled: true,
watchCacheRV: "2",
storageRV: "42",
expectRV: "42",
@ -414,7 +387,6 @@ apiserver_watch_cache_consistent_read_total{fallback="true", group="", resource=
},
{
name: "Fallback Failure",
consistentReadsEnabled: true,
watchCacheRV: "2",
storageRV: "42",
fallbackError: true,
@ -429,7 +401,6 @@ apiserver_watch_cache_consistent_read_total{fallback="true", group="", resource=
},
{
name: "Skip Storage Fallback",
consistentReadsEnabled: true,
skipStorageFallback: true,
watchCacheRV: "2",
storageRV: "42",
@ -443,23 +414,10 @@ apiserver_watch_cache_consistent_read_total{fallback="true", group="", resource=
apiserver_watch_cache_consistent_read_total{fallback="skipped", group="", resource="pods", success="false"} 1
`,
},
{
name: "Disabled",
watchCacheRV: "2",
storageRV: "42",
expectRV: "42",
expectRequestsToStorage: 1,
expectMetric: ``,
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
if tc.consistentReadsEnabled {
forceRequestWatchProgressSupport(t)
} else {
featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.33"))
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ConsistentListFromCache, false)
}
forceRequestWatchProgressSupport(t)
if tc.skipStorageFallback {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ConsistentListFromCacheSkipTimeoutFallback, true)
}
@ -646,53 +604,10 @@ func TestMatchExactResourceVersionFallback(t *testing.T) {
}
}
func TestGetListNonRecursiveCacheBypass(t *testing.T) {
featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.33"))
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ConsistentListFromCache, false)
backingStorage := &cachertesting.MockStorage{}
cacher, _, err := newTestCacher(backingStorage)
if err != nil {
t.Fatalf("Couldn't create cacher: %v", err)
}
defer cacher.Stop()
delegator := NewCacheDelegator(cacher, backingStorage)
defer delegator.Stop()
pred := storage.SelectionPredicate{
Limit: 500,
}
result := &example.PodList{}
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
// Inject error to underlying layer and check if cacher is not bypassed.
backingStorage.InjectGetListError(errDummy)
err = delegator.GetList(context.TODO(), "/pods/ns", storage.ListOptions{
ResourceVersion: "0",
Predicate: pred,
}, result)
if err != nil {
t.Errorf("GetList with Limit and RV=0 should be served from cache: %v", err)
}
err = delegator.GetList(context.TODO(), "/pods/ns", storage.ListOptions{
ResourceVersion: "",
Predicate: pred,
}, result)
if !errors.Is(err, errDummy) {
t.Errorf("GetList with Limit without RV=0 should bypass cacher: %v", err)
}
}
func TestGetListNonRecursiveCacheWithConsistentListFromCache(t *testing.T) {
// Set feature gates once at the beginning since we only care about ConsistentListFromCache=true and ListFromCacheSnapshot=false
// Set feature gates once at the beginning since we only care about ListFromCacheSnapshot=false
featuregatetesting.SetFeatureGatesDuringTest(t, utilfeature.DefaultFeatureGate, featuregatetesting.FeatureOverrides{
features.ConsistentListFromCache: true,
features.ListFromCacheSnapshot: false,
features.ListFromCacheSnapshot: false,
})
forceRequestWatchProgressSupport(t)
@ -821,12 +736,6 @@ func TestGetCacheBypass(t *testing.T) {
result := &example.Pod{}
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
// Inject error to underlying layer and check if cacher is not bypassed.
backingStorage.InjectGetListError(errDummy)
err = delegator.Get(context.TODO(), "/pods/ns/pod-0", storage.GetOptions{
@ -856,12 +765,6 @@ func TestWatchCacheBypass(t *testing.T) {
delegator := NewCacheDelegator(cacher, backingStorage)
defer delegator.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
_, err = delegator.Watch(context.TODO(), "/pods/ns", storage.ListOptions{
ResourceVersion: "0",
Predicate: storage.Everything,
@ -879,46 +782,6 @@ func TestWatchCacheBypass(t *testing.T) {
}
}
func TestTooManyRequestsNotReturned(t *testing.T) {
// Ensure that with ResilientWatchCacheInitialization feature disabled, we don't return 429
// errors when watchcache is not initialized.
featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.33"))
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ResilientWatchCacheInitialization, false)
dummyErr := fmt.Errorf("dummy")
backingStorage := &cachertesting.MockStorage{GetListErr: dummyErr}
cacher, _, err := newTestCacherWithoutSyncing(backingStorage, clock.RealClock{})
if err != nil {
t.Fatalf("Couldn't create cacher: %v", err)
}
defer cacher.Stop()
delegator := NewCacheDelegator(cacher, backingStorage)
defer delegator.Stop()
opts := storage.ListOptions{
ResourceVersion: "0",
Predicate: storage.Everything,
}
// Cancel the request so that it doesn't hang forever.
listCtx, listCancel := context.WithTimeout(context.Background(), 250*time.Millisecond)
defer listCancel()
result := &example.PodList{}
err = delegator.GetList(listCtx, "/pods/ns", opts, result)
if err != nil && apierrors.IsTooManyRequests(err) {
t.Errorf("Unexpected 429 error without ResilientWatchCacheInitialization feature for List")
}
watchCtx, watchCancel := context.WithTimeout(context.Background(), 250*time.Millisecond)
defer watchCancel()
_, err = delegator.Watch(watchCtx, "/pods/ns", opts)
if err != nil && apierrors.IsTooManyRequests(err) {
t.Errorf("Unexpected 429 error without ResilientWatchCacheInitialization feature for Watch")
}
}
func TestEmptyWatchEventCache(t *testing.T) {
server, etcdStorage := newEtcdTestStorage(t, etcd3testing.PathPrefix())
defer server.Terminate(t)
@ -1033,14 +896,8 @@ func TestWatchNotHangingOnStartupFailure(t *testing.T) {
// Ensure that it terminates when its context is cancelled
// (e.g. the request is terminated for whatever reason).
_, err = cacher.Watch(ctx, "/pods/ns", storage.ListOptions{ResourceVersion: "0"})
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err == nil || err.Error() != apierrors.NewServiceUnavailable(context.Canceled.Error()).Error() {
t.Errorf("Unexpected error: %#v", err)
}
} else {
if err == nil || !strings.Contains(err.Error(), "storage is (re)initializing") {
t.Errorf("Unexpected error: %#v", err)
}
if err == nil || !strings.Contains(err.Error(), "storage is (re)initializing") {
t.Errorf("Unexpected error: %#v", err)
}
}
@ -1052,12 +909,6 @@ func TestWatcherNotGoingBackInTime(t *testing.T) {
}
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
// Ensure there is some budget for slowing down processing.
cacher.dispatchTimeoutBudget.returnUnused(100 * time.Millisecond)
@ -1141,12 +992,6 @@ func TestCacherDontAcceptRequestsStopped(t *testing.T) {
delegator := NewCacheDelegator(cacher, backingStorage)
defer delegator.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
w, err := delegator.Watch(context.Background(), "/pods/ns", storage.ListOptions{ResourceVersion: "0", Predicate: storage.Everything})
if err != nil {
t.Fatalf("Failed to create watch: %v", err)
@ -1177,14 +1022,8 @@ func TestCacherDontAcceptRequestsStopped(t *testing.T) {
IgnoreNotFound: true,
ResourceVersion: "1",
}, result)
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err == nil {
t.Fatalf("Success to create Get: %v", err)
}
} else {
if err != nil {
t.Fatalf("Failed to get object: %v:", err)
}
if err != nil {
t.Fatalf("Failed to get object: %v:", err)
}
listResult := &example.PodList{}
@ -1195,14 +1034,8 @@ func TestCacherDontAcceptRequestsStopped(t *testing.T) {
Limit: 500,
},
}, listResult)
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err != nil {
t.Fatalf("Failed to create GetList: %v", err)
}
} else {
if err != nil {
t.Fatalf("Failed to list objects: %v", err)
}
if err != nil {
t.Fatalf("Failed to list objects: %v", err)
}
select {
@ -1329,12 +1162,6 @@ func TestCacherNoLeakWithMultipleWatchers(t *testing.T) {
}
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
pred := storage.Everything
pred.AllowWatchBookmarks = true
@ -1410,11 +1237,6 @@ func testCacherSendBookmarkEvents(t *testing.T, allowWatchBookmarks, expectedBoo
}
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
pred := storage.Everything
pred.AllowWatchBookmarks = allowWatchBookmarks
@ -1510,12 +1332,6 @@ func TestInitialEventsEndBookmark(t *testing.T) {
}
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
makePod := func(index uint64) *example.Pod {
return &example.Pod{
ObjectMeta: metav1.ObjectMeta{
@ -1611,11 +1427,6 @@ func TestCacherSendsMultipleWatchBookmarks(t *testing.T) {
// resolution how frequency we recompute.
cacher.bookmarkWatchers.bookmarkFrequency = time.Second
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
pred := storage.Everything
pred.AllowWatchBookmarks = true
@ -1682,12 +1493,6 @@ func TestDispatchingBookmarkEventsWithConcurrentStop(t *testing.T) {
}
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
// Ensure there is some budget for slowing down processing.
cacher.dispatchTimeoutBudget.returnUnused(100 * time.Millisecond)
@ -1761,12 +1566,6 @@ func TestBookmarksOnResourceVersionUpdates(t *testing.T) {
// Ensure that bookmarks are sent more frequently than every 1m.
cacher.bookmarkWatchers = newTimeBucketWatchers(clock.RealClock{}, 2*time.Second)
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
makePod := func(i int) *examplev1.Pod {
return &examplev1.Pod{
ObjectMeta: metav1.ObjectMeta{
@ -1840,12 +1639,6 @@ func TestStartingResourceVersion(t *testing.T) {
}
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
// Ensure there is some budget for slowing down processing.
// We use the fakeTimeBudget to prevent this test from flaking under
// the following conditions:
@ -1921,12 +1714,6 @@ func TestDispatchEventWillNotBeBlockedByTimedOutWatcher(t *testing.T) {
}
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
// Ensure there is some budget for slowing down processing.
// We use the fakeTimeBudget to prevent this test from flaking under
// the following conditions:
@ -2064,12 +1851,6 @@ func TestCachingDeleteEvents(t *testing.T) {
}
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
fooPredicate := storage.SelectionPredicate{
Label: labels.SelectorFromSet(map[string]string{"foo": "true"}),
Field: fields.Everything(),
@ -2147,12 +1928,6 @@ func testCachingObjects(t *testing.T, watchersCount int) {
}
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
dispatchedEvents := []*watchCacheEvent{}
cacher.watchCache.eventHandler = func(event *watchCacheEvent) {
dispatchedEvents = append(dispatchedEvents, event)
@ -2244,12 +2019,6 @@ func TestCacheIntervalInvalidationStopsWatch(t *testing.T) {
}
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
// Ensure there is enough budget for slow processing since
// the entire watch cache is going to be served through the
// interval and events won't be popped from the cacheWatcher's
@ -2324,8 +2093,7 @@ func TestCacheIntervalInvalidationStopsWatch(t *testing.T) {
func TestWaitUntilWatchCacheFreshAndForceAllEvents(t *testing.T) {
featuregatetesting.SetFeatureGatesDuringTest(t, utilfeature.DefaultFeatureGate, featuregatetesting.FeatureOverrides{
features.WatchList: true,
features.ConsistentListFromCache: true,
features.WatchList: true,
})
forceRequestWatchProgressSupport(t)
@ -2455,12 +2223,6 @@ func TestWaitUntilWatchCacheFreshAndForceAllEvents(t *testing.T) {
}
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
w, err := cacher.Watch(context.Background(), "/pods/ns", scenario.opts)
require.NoError(t, err, "failed to create watch: %v")
defer w.Stop()
@ -2619,12 +2381,6 @@ func TestWatchListIsSynchronisedWhenNoEventsFromStoreReceived(t *testing.T) {
require.NoError(t, err, "failed to create cacher")
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
pred := storage.Everything
pred.AllowWatchBookmarks = true
opts := storage.ListOptions{
@ -2651,12 +2407,6 @@ func TestForgetWatcher(t *testing.T) {
require.NoError(t, err)
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
assertCacherInternalState := func(expectedWatchersCounter, expectedValueWatchersCounter int) {
cacher.Lock()
defer cacher.Unlock()
@ -3045,12 +2795,6 @@ func TestGetBookmarkAfterResourceVersionLockedFunc(t *testing.T) {
defer cacher.Stop()
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if err := cacher.ready.wait(context.Background()); err != nil {
t.Fatalf("unexpected error waiting for the cache to be ready")
}
}
cacher.watchCache.UpdateResourceVersion(fmt.Sprintf("%d", scenario.watchCacheResourceVersion))
parsedResourceVersion := 0
if len(scenario.opts.ResourceVersion) > 0 {
@ -3291,9 +3035,6 @@ func TestListIndexer(t *testing.T) {
}
func TestRetryAfterForUnreadyCache(t *testing.T) {
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
t.Skipf("the test requires %v to be enabled", features.ResilientWatchCacheInitialization)
}
backingStorage := &cachertesting.MockStorage{}
clock := testingclock.NewFakeClock(time.Now())
cacher, _, err := newTestCacherWithoutSyncing(backingStorage, clock)

View file

@ -146,33 +146,18 @@ func (c *CacheDelegator) Get(ctx context.Context, key string, opts storage.GetOp
return c.storage.Get(ctx, key, opts, objPtr)
}
if utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if !c.cacher.Ready() {
// If Cache is not initialized, delegator Get requests to storage
// as described in https://kep.k8s.io/4568
span.AddEvent("About to Get from underlying storage - cache not initialized")
return c.storage.Get(ctx, key, opts, objPtr)
}
if !c.cacher.Ready() {
// If Cache is not initialized, delegator Get requests to storage
// as described in https://kep.k8s.io/4568
span.AddEvent("About to Get from underlying storage - cache not initialized")
return c.storage.Get(ctx, key, opts, objPtr)
}
// If resourceVersion is specified, serve it from cache.
// It's guaranteed that the returned value is at least that
// fresh as the given resourceVersion.
getRV, err := c.cacher.versioner.ParseResourceVersion(opts.ResourceVersion)
if err != nil {
if _, err := c.cacher.versioner.ParseResourceVersion(opts.ResourceVersion); err != nil {
return err
}
// Do not create a trace - it's not for free and there are tons
// of Get requests. We can add it if it will be really needed.
if !utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if getRV == 0 && !c.cacher.Ready() {
// If Cacher is not yet initialized and we don't require any specific
// minimal resource version, simply forward the request to storage.
return c.storage.Get(ctx, key, opts, objPtr)
}
if err := c.cacher.ready.wait(ctx); err != nil {
return errors.NewServiceUnavailable(err.Error())
}
}
span.AddEvent("About to fetch object from cache")
return c.cacher.Get(ctx, key, opts, objPtr)
}
@ -190,23 +175,14 @@ func (c *CacheDelegator) GetList(ctx context.Context, key string, opts storage.L
return c.storage.GetList(ctx, key, opts, listObj)
}
listRV, err := c.cacher.versioner.ParseResourceVersion(opts.ResourceVersion)
if err != nil {
if _, err := c.cacher.versioner.ParseResourceVersion(opts.ResourceVersion); err != nil {
return err
}
if utilfeature.DefaultFeatureGate.Enabled(features.ResilientWatchCacheInitialization) {
if !c.cacher.Ready() && shouldDelegateListOnNotReadyCache(opts) {
// If Cacher is not initialized, delegator List requests to storage
// as described in https://kep.k8s.io/4568
return c.storage.GetList(ctx, key, opts, listObj)
}
} else {
if listRV == 0 && !c.cacher.Ready() {
// If Cacher is not yet initialized and we don't require any specific
// minimal resource version, simply forward the request to storage.
return c.storage.GetList(ctx, key, opts, listObj)
}
if !c.cacher.Ready() && shouldDelegateListOnNotReadyCache(opts) {
// If Cacher is not initialized, delegator List requests to storage
// as described in https://kep.k8s.io/4568
return c.storage.GetList(ctx, key, opts, listObj)
}
err = c.cacher.GetList(ctx, key, opts, listObj)
success := "true"

View file

@ -18,10 +18,8 @@ package delegator
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apiserver/pkg/features"
"k8s.io/apiserver/pkg/storage"
etcdfeature "k8s.io/apiserver/pkg/storage/feature"
utilfeature "k8s.io/apiserver/pkg/util/feature"
)
func ShouldDelegateListMeta(opts *metav1.ListOptions, cache Helper) (Result, error) {
@ -107,7 +105,5 @@ func (c CacheWithoutSnapshots) ShouldDelegateConsistentRead() (Result, error) {
// ConsistentReadSupported returns whether cache can be used to serve reads with RV not yet observed by cache, including both consistent reads.
// Function is located here to avoid import cycles between staging/src/k8s.io/apiserver/pkg/storage/cacher/delegator.go and staging/src/k8s.io/apiserver/pkg/util/flow_control/request/list_work_estimator.go.
func ConsistentReadSupported() bool {
consistentListFromCacheEnabled := utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache)
requestWatchProgressSupported := etcdfeature.DefaultFeatureSupportChecker.Supports(storage.RequestWatchProgress)
return consistentListFromCacheEnabled && requestWatchProgressSupported
return etcdfeature.DefaultFeatureSupportChecker.Supports(storage.RequestWatchProgress)
}

View file

@ -22,8 +22,6 @@ import (
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apiserver/pkg/features"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/tools/cache"
)
@ -79,10 +77,7 @@ type OrderedLister interface {
}
func NewIndexer(indexers *cache.Indexers) Indexer {
if utilfeature.DefaultFeatureGate.Enabled(features.BtreeWatchCache) {
return newThreadedBtreeStoreIndexer(ElementIndexers(indexers), btreeDegree)
}
return cache.NewIndexer(ElementKey, ElementIndexers(indexers))
return newThreadedBtreeStoreIndexer(ElementIndexers(indexers), btreeDegree)
}
// Computing a key of an object is generally non-trivial (it performs

View file

@ -35,7 +35,6 @@ import (
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/util/version"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/apimachinery/pkg/watch"
"k8s.io/apiserver/pkg/features"
@ -554,7 +553,6 @@ func TestWaitUntilFreshAndGetList(t *testing.T) {
}
func TestWaitUntilFreshAndListFromCache(t *testing.T) {
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ConsistentListFromCache, true)
forceRequestWatchProgressSupport(t)
ctx := context.Background()
store := newTestWatchCache(3, DefaultEventFreshDuration, &cache.Indexers{})
@ -609,54 +607,33 @@ func TestWaitUntilFreshAndGet(t *testing.T) {
}
func TestWaitUntilFreshAndListTimeout(t *testing.T) {
tcs := []struct {
name string
ConsistentListFromCache bool
}{
{
name: "FromStorage",
ConsistentListFromCache: false,
},
{
name: "FromCache",
ConsistentListFromCache: true,
},
ctx := context.Background()
store := newTestWatchCache(3, DefaultEventFreshDuration, &cache.Indexers{})
defer store.Stop()
fc := store.clock.(*testingclock.FakeClock)
// In background, step clock after the below call starts the timer.
go func() {
for !fc.HasWaiters() {
time.Sleep(time.Millisecond)
}
store.Add(makeTestPod("foo", 2))
store.bookmarkRevision <- 3
fc.Step(blockTimeout)
// Add an object to make sure the test would
// eventually fail instead of just waiting
// forever.
time.Sleep(30 * time.Second)
store.Add(makeTestPod("bar", 4))
}()
_, _, err := store.WaitUntilFreshAndGetList(ctx, "", storage.ListOptions{ResourceVersion: "4", Predicate: storage.Everything})
if !errors.IsTimeout(err) {
t.Errorf("expected timeout error but got: %v", err)
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
if !tc.ConsistentListFromCache {
featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.33"))
featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.ConsistentListFromCache, tc.ConsistentListFromCache)
}
ctx := context.Background()
store := newTestWatchCache(3, DefaultEventFreshDuration, &cache.Indexers{})
defer store.Stop()
fc := store.clock.(*testingclock.FakeClock)
// In background, step clock after the below call starts the timer.
go func() {
for !fc.HasWaiters() {
time.Sleep(time.Millisecond)
}
store.Add(makeTestPod("foo", 2))
store.bookmarkRevision <- 3
fc.Step(blockTimeout)
// Add an object to make sure the test would
// eventually fail instead of just waiting
// forever.
time.Sleep(30 * time.Second)
store.Add(makeTestPod("bar", 4))
}()
_, _, err := store.WaitUntilFreshAndGetList(ctx, "", storage.ListOptions{ResourceVersion: "4", Predicate: storage.Everything})
if !errors.IsTimeout(err) {
t.Errorf("expected timeout error but got: %v", err)
}
if !storage.IsTooLargeResourceVersion(err) {
t.Errorf("expected 'Too large resource version' cause in error but got: %v", err)
}
})
if !storage.IsTooLargeResourceVersion(err) {
t.Errorf("expected 'Too large resource version' cause in error but got: %v", err)
}
}

View file

@ -200,9 +200,7 @@ func New(c *kubernetes.Client, compactor Compactor, codec runtime.Codec, newFunc
w.getCurrentStorageRV = func(ctx context.Context) (uint64, error) {
return s.GetCurrentResourceVersion(ctx)
}
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) || utilfeature.DefaultFeatureGate.Enabled(features.WatchList) {
etcdfeature.DefaultFeatureSupportChecker.CheckClient(c.Ctx(), c, storage.RequestWatchProgress)
}
etcdfeature.DefaultFeatureSupportChecker.CheckClient(c.Ctx(), c, storage.RequestWatchProgress)
return s, nil
}

View file

@ -319,17 +319,15 @@ var newETCD3Client = func(c storagebackend.TransportConfig) (*kubernetes.Client,
grpc.WithChainUnaryInterceptor(grpcpromClientMetrics.UnaryClientInterceptor()),
grpc.WithChainStreamInterceptor(grpcpromClientMetrics.StreamClientInterceptor()),
}
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerTracing) {
tracingOpts := []otelgrpc.Option{
otelgrpc.WithMessageEvents(otelgrpc.ReceivedEvents, otelgrpc.SentEvents),
otelgrpc.WithPropagators(tracing.Propagators()),
otelgrpc.WithTracerProvider(c.TracerProvider),
}
// Even with Noop TracerProvider, the otelgrpc still handles context propagation.
// See https://github.com/open-telemetry/opentelemetry-go/tree/main/example/passthrough
dialOptions = append(dialOptions,
grpc.WithStatsHandler(otelgrpc.NewClientHandler(tracingOpts...)))
tracingOpts := []otelgrpc.Option{
otelgrpc.WithMessageEvents(otelgrpc.ReceivedEvents, otelgrpc.SentEvents),
otelgrpc.WithPropagators(tracing.Propagators()),
otelgrpc.WithTracerProvider(c.TracerProvider),
}
// Even with Noop TracerProvider, the otelgrpc still handles context propagation.
// See https://github.com/open-telemetry/opentelemetry-go/tree/main/example/passthrough
dialOptions = append(dialOptions,
grpc.WithStatsHandler(otelgrpc.NewClientHandler(tracingOpts...)))
if egressDialer != nil {
dialer := func(ctx context.Context, addr string) (net.Conn, error) {
if strings.Contains(addr, "//") {

View file

@ -709,14 +709,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
pred: storage.Everything,
expectedOut: []example.Pod{*updatedPod},
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
return nil
}
return []RecordedList{
{
Key: "/registry/pods/first/",
},
}
return nil
},
},
{
@ -878,14 +871,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
pred: storage.Everything,
expectedOut: []example.Pod{},
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
return nil
}
return []RecordedList{
{
Key: "/registry/pods/non-existing/",
},
}
return nil
},
},
{
@ -897,14 +883,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
},
expectedOut: []example.Pod{},
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
return nil
}
return []RecordedList{
{
Key: "/registry/pods/first/",
},
}
return nil
},
},
{
@ -932,15 +911,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
expectContinueExact: encodeContinueOrDie(createdPods[1].Name+"\x00", int64(mustAtoi(currentRV))),
expectedRemainingItemCount: ptr.To[int64](1),
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
return nil
}
return []RecordedList{
{
Key: "/registry/pods/second/",
ListOptions: kubernetes.ListOptions{Revision: 0, Limit: 1},
},
}
return nil
},
},
{
@ -1151,14 +1122,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
pred: storage.Everything,
expectedOut: []example.Pod{*createdPods[1], *createdPods[2]},
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
return nil
}
return []RecordedList{
{
Key: "/registry/pods/second/",
},
}
return nil
},
},
{
@ -1180,23 +1144,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
expectedOut: []example.Pod{*createdPods[3]},
expectContinue: true,
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
return nil
}
return []RecordedList{
{
Key: "/registry/pods/",
ListOptions: kubernetes.ListOptions{Limit: 1},
},
{
Key: "/registry/pods/",
ListOptions: kubernetes.ListOptions{Revision: int64(continueRV) + 1, Limit: 2, Continue: "/registry/pods/first/bar\x00"},
},
{
Key: "/registry/pods/",
ListOptions: kubernetes.ListOptions{Revision: int64(continueRV) + 1, Limit: 4, Continue: "/registry/pods/second/foo\x00"},
},
}
return nil
},
},
{
@ -1224,19 +1172,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
expectedOut: []example.Pod{*createdPods[3]},
expectContinue: false,
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
return nil
}
return []RecordedList{
{
Key: "/registry/pods/",
ListOptions: kubernetes.ListOptions{Revision: 0, Limit: 2},
},
{
Key: "/registry/pods/",
ListOptions: kubernetes.ListOptions{Revision: int64(continueRV) + 1, Limit: 4, Continue: "/registry/pods/second/bar\x00"},
},
}
return nil
},
},
{
@ -1276,15 +1212,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
expectContinue: true,
expectedOut: []example.Pod{*updatedPod, *createdPods[1]},
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
return nil
}
return []RecordedList{
{
Key: "/registry/pods/",
ListOptions: kubernetes.ListOptions{Revision: 0, Limit: 2},
},
}
return nil
},
},
{
@ -1310,19 +1238,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
},
expectedOut: []example.Pod{*createdPods[2], *createdPods[4]},
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
return nil
}
return []RecordedList{
{
Key: "/registry/pods/",
ListOptions: kubernetes.ListOptions{Revision: 0, Limit: 2},
},
{
Key: "/registry/pods/",
ListOptions: kubernetes.ListOptions{Revision: int64(continueRV) + 1, Limit: 4, Continue: "/registry/pods/second/bar\x00"},
},
}
return nil
},
},
{
@ -1417,15 +1333,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
},
expectedOut: []example.Pod{*createdPods[2], *createdPods[4]},
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
return nil
}
return []RecordedList{
{
Key: "/registry/pods/",
ListOptions: kubernetes.ListOptions{Revision: 0, Limit: 5},
},
}
return nil
},
},
{
@ -1450,15 +1358,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
},
expectedOut: []example.Pod{*createdPods[3]},
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
return nil
}
return []RecordedList{
{
Key: "/registry/pods/",
ListOptions: kubernetes.ListOptions{Revision: 0, Limit: 5},
},
}
return nil
},
},
{
@ -1479,14 +1379,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
pred: storage.Everything,
expectedOut: []example.Pod{*updatedPod, *createdPods[1], *createdPods[2], *createdPods[3], *createdPods[4]},
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
return nil
}
return []RecordedList{
{
Key: "/registry/pods/",
},
}
return nil
},
},
{
@ -1529,14 +1422,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
expectRV: currentRV,
expectedOut: []example.Pod{},
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) {
return nil
}
return []RecordedList{
{
Key: "/registry/pods/empty/",
},
}
return nil
},
},
{
@ -1725,7 +1611,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
rvMatch: metav1.ResourceVersionMatchExact,
expectRV: fmt.Sprint(continueRV + 1),
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) && utilfeature.DefaultFeatureGate.Enabled(features.ListFromCacheSnapshot) {
if utilfeature.DefaultFeatureGate.Enabled(features.ListFromCacheSnapshot) {
return nil
}
return []RecordedList{
@ -1955,7 +1841,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
expectContinueExact: encodeContinueOrDie(updatedPod.Namespace+"/"+updatedPod.Name+"\x00", int64(continueRV+1)),
expectedRemainingItemCount: ptr.To[int64](4),
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) && utilfeature.DefaultFeatureGate.Enabled(features.ListFromCacheSnapshot) {
if utilfeature.DefaultFeatureGate.Enabled(features.ListFromCacheSnapshot) {
return nil
}
return []RecordedList{
@ -2148,7 +2034,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
expectContinueExact: encodeContinueOrDie(createdPods[1].Namespace+"/"+createdPods[1].Name+"\x00", int64(continueRV+1)),
expectedRemainingItemCount: ptr.To[int64](3),
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) && utilfeature.DefaultFeatureGate.Enabled(features.ListFromCacheSnapshot) {
if utilfeature.DefaultFeatureGate.Enabled(features.ListFromCacheSnapshot) {
return nil
}
return []RecordedList{
@ -2170,7 +2056,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
expectedOut: []example.Pod{*createdPods[1], *createdPods[2], *createdPods[3], *createdPods[4]},
expectRV: currentRV,
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) && utilfeature.DefaultFeatureGate.Enabled(features.ListFromCacheSnapshot) {
if utilfeature.DefaultFeatureGate.Enabled(features.ListFromCacheSnapshot) {
return nil
}
return []RecordedList{
@ -2196,7 +2082,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
expectRV: currentRV,
expectedRemainingItemCount: ptr.To[int64](2),
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) && utilfeature.DefaultFeatureGate.Enabled(features.ListFromCacheSnapshot) {
if utilfeature.DefaultFeatureGate.Enabled(features.ListFromCacheSnapshot) {
return nil
}
return []RecordedList{
@ -2218,7 +2104,7 @@ func RunTestList(ctx context.Context, t *testing.T, store storage.Interface, com
expectedOut: []example.Pod{*createdPods[3], *createdPods[4]},
expectRV: currentRV,
expectCacherRequestsToEtcd: func() []RecordedList {
if utilfeature.DefaultFeatureGate.Enabled(features.ConsistentListFromCache) && utilfeature.DefaultFeatureGate.Enabled(features.ListFromCacheSnapshot) {
if utilfeature.DefaultFeatureGate.Enabled(features.ListFromCacheSnapshot) {
return nil
}
return []RecordedList{

View file

@ -29,9 +29,7 @@ import (
corev1 "k8s.io/api/core/v1"
utilnet "k8s.io/apimachinery/pkg/util/net"
"k8s.io/apiserver/pkg/features"
egressselector "k8s.io/apiserver/pkg/server/egressselector"
"k8s.io/apiserver/pkg/util/feature"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
@ -59,9 +57,7 @@ func NewDefaultAuthenticationInfoResolverWrapper(
if err != nil {
return nil, err
}
if feature.DefaultFeatureGate.Enabled(features.APIServerTracing) {
ret.Wrap(tracing.WrapperFor(tp))
}
ret.Wrap(tracing.WrapperFor(tp))
if egressSelector != nil {
networkContext := egressselector.ControlPlane.AsNetworkContext()
@ -84,9 +80,7 @@ func NewDefaultAuthenticationInfoResolverWrapper(
if err != nil {
return nil, err
}
if feature.DefaultFeatureGate.Enabled(features.APIServerTracing) {
ret.Wrap(tracing.WrapperFor(tp))
}
ret.Wrap(tracing.WrapperFor(tp))
if egressSelector != nil {
networkContext := egressselector.Cluster.AsNetworkContext()

View file

@ -167,7 +167,7 @@ func (r *proxyHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
proxyRoundTripper = transport.NewAuthProxyRoundTripper(user.GetName(), userUID, user.GetGroups(), user.GetExtra(), proxyRoundTripper)
if utilfeature.DefaultFeatureGate.Enabled(genericfeatures.APIServerTracing) && !upgrade {
if !upgrade {
tracingWrapper := tracing.WrapperFor(r.tracerProvider)
proxyRoundTripper = tracingWrapper(proxyRoundTripper)
}

View file

@ -7,7 +7,6 @@
|---------|---------|--------|-------|------|----|------------|--------------|-------|
| APIResponseCompression | :ballot_box_with_check:&nbsp;1.16+ | | 1.81.15 | 1.16 | | | | [code](https://cs.k8s.io/?q=%5CbAPIResponseCompression%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAPIResponseCompression%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| APIServerIdentity | :ballot_box_with_check:&nbsp;1.26+ | | 1.201.25 | 1.26 | | | | [code](https://cs.k8s.io/?q=%5CbAPIServerIdentity%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAPIServerIdentity%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| APIServerTracing | :ballot_box_with_check:&nbsp;1.27+ | :closed_lock_with_key:&nbsp;1.34+ | 1.221.26 | 1.271.33 | 1.34 | | | [code](https://cs.k8s.io/?q=%5CbAPIServerTracing%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAPIServerTracing%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| APIServingWithRoutine | | | 1.30 | | | | | [code](https://cs.k8s.io/?q=%5CbAPIServingWithRoutine%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAPIServingWithRoutine%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| AggregatedDiscoveryRemoveBetaType | :ballot_box_with_check:&nbsp;1.33+ | :closed_lock_with_key:&nbsp;1.35+ | | | 1.01.32 | 1.33 | | [code](https://cs.k8s.io/?q=%5CbAggregatedDiscoveryRemoveBetaType%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAggregatedDiscoveryRemoveBetaType%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| AllowDNSOnlyNodeCSR | :ballot_box_with_check:&nbsp;1.0+ | | | | 1.01.30 | 1.31 | | [code](https://cs.k8s.io/?q=%5CbAllowDNSOnlyNodeCSR%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAllowDNSOnlyNodeCSR%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
@ -18,7 +17,6 @@
| AllowUnsafeMalformedObjectDeletion | | | 1.32 | | | | | [code](https://cs.k8s.io/?q=%5CbAllowUnsafeMalformedObjectDeletion%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAllowUnsafeMalformedObjectDeletion%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| AtomicFIFO | :ballot_box_with_check:&nbsp;1.36+ | | | 1.36 | | | | [code](https://cs.k8s.io/?q=%5CbAtomicFIFO%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAtomicFIFO%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| AuthorizePodWebsocketUpgradeCreatePermission | :ballot_box_with_check:&nbsp;1.35+ | | | 1.35 | | | | [code](https://cs.k8s.io/?q=%5CbAuthorizePodWebsocketUpgradeCreatePermission%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbAuthorizePodWebsocketUpgradeCreatePermission%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| BtreeWatchCache | :ballot_box_with_check:&nbsp;1.32+ | :closed_lock_with_key:&nbsp;1.33+ | | 1.32 | 1.33 | | | [code](https://cs.k8s.io/?q=%5CbBtreeWatchCache%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbBtreeWatchCache%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| CBORServingAndStorage | | | 1.32 | | | | | [code](https://cs.k8s.io/?q=%5CbCBORServingAndStorage%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbCBORServingAndStorage%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| CPUManagerPolicyAlphaOptions | | | 1.23 | | | | | [code](https://cs.k8s.io/?q=%5CbCPUManagerPolicyAlphaOptions%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbCPUManagerPolicyAlphaOptions%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| CPUManagerPolicyBetaOptions | :ballot_box_with_check:&nbsp;1.23+ | | | 1.23 | | | | [code](https://cs.k8s.io/?q=%5CbCPUManagerPolicyBetaOptions%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbCPUManagerPolicyBetaOptions%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
@ -41,8 +39,7 @@
| ComponentFlagz | :ballot_box_with_check:&nbsp;1.36+ | | 1.321.35 | 1.36 | | | | [code](https://cs.k8s.io/?q=%5CbComponentFlagz%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbComponentFlagz%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| ComponentStatusz | :ballot_box_with_check:&nbsp;1.36+ | | 1.321.35 | 1.36 | | | | [code](https://cs.k8s.io/?q=%5CbComponentStatusz%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbComponentStatusz%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| ConcurrentWatchObjectDecode | | | | 1.31 | | | | [code](https://cs.k8s.io/?q=%5CbConcurrentWatchObjectDecode%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbConcurrentWatchObjectDecode%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| ConsistentListFromCache | :ballot_box_with_check:&nbsp;1.31+ | :closed_lock_with_key:&nbsp;1.34+ | 1.281.30 | 1.311.33 | 1.34 | | | [code](https://cs.k8s.io/?q=%5CbConsistentListFromCache%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbConsistentListFromCache%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| ConsistentListFromCacheSkipTimeoutFallback | | | 1.37 | | | | ConsistentListFromCache | [code](https://cs.k8s.io/?q=%5CbConsistentListFromCacheSkipTimeoutFallback%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbConsistentListFromCacheSkipTimeoutFallback%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| ConsistentListFromCacheSkipTimeoutFallback | | | 1.37 | | | | | [code](https://cs.k8s.io/?q=%5CbConsistentListFromCacheSkipTimeoutFallback%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbConsistentListFromCacheSkipTimeoutFallback%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| ConstrainedImpersonation | :ballot_box_with_check:&nbsp;1.36+ | | 1.35 | 1.36 | | | | [code](https://cs.k8s.io/?q=%5CbConstrainedImpersonation%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbConstrainedImpersonation%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| ContainerCheckpoint | :ballot_box_with_check:&nbsp;1.30+ | | 1.251.29 | 1.30 | | | | [code](https://cs.k8s.io/?q=%5CbContainerCheckpoint%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbContainerCheckpoint%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| ContainerRestartRules | :ballot_box_with_check:&nbsp;1.35+ | | 1.34 | 1.35 | | | | [code](https://cs.k8s.io/?q=%5CbContainerRestartRules%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbContainerRestartRules%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
@ -138,7 +135,6 @@
| NominatedNodeNameForExpectation | :ballot_box_with_check:&nbsp;1.35+ | | 1.34 | 1.35 | | | | [code](https://cs.k8s.io/?q=%5CbNominatedNodeNameForExpectation%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbNominatedNodeNameForExpectation%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| OpenAPIEnums | :ballot_box_with_check:&nbsp;1.24+ | | 1.23 | 1.24 | | | | [code](https://cs.k8s.io/?q=%5CbOpenAPIEnums%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbOpenAPIEnums%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| OpportunisticBatching | :ballot_box_with_check:&nbsp;1.35+ | | | 1.35 | | | | [code](https://cs.k8s.io/?q=%5CbOpportunisticBatching%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbOpportunisticBatching%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| OrderedNamespaceDeletion | :ballot_box_with_check:&nbsp;1.33+ | :closed_lock_with_key:&nbsp;1.34+ | | 1.301.33 | 1.34 | | | [code](https://cs.k8s.io/?q=%5CbOrderedNamespaceDeletion%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbOrderedNamespaceDeletion%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| PLEGOnDemandRelist | :ballot_box_with_check:&nbsp;1.36+ | | | 1.36 | | | | [code](https://cs.k8s.io/?q=%5CbPLEGOnDemandRelist%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbPLEGOnDemandRelist%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| PersistentVolumeClaimUnusedSinceTime | | | 1.36 | | | | | [code](https://cs.k8s.io/?q=%5CbPersistentVolumeClaimUnusedSinceTime%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbPersistentVolumeClaimUnusedSinceTime%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| PodAndContainerStatsFromCRI | | | 1.23 | | | | | [code](https://cs.k8s.io/?q=%5CbPodAndContainerStatsFromCRI%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbPodAndContainerStatsFromCRI%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
@ -168,11 +164,9 @@
| ReloadKubeletClientCAFile | :ballot_box_with_check:&nbsp;1.36+ | | | 1.36 | | | | [code](https://cs.k8s.io/?q=%5CbReloadKubeletClientCAFile%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbReloadKubeletClientCAFile%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| ReloadKubeletServerCertificateFile | :ballot_box_with_check:&nbsp;1.31+ | | | 1.31 | | | | [code](https://cs.k8s.io/?q=%5CbReloadKubeletServerCertificateFile%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbReloadKubeletServerCertificateFile%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| RemoteRequestHeaderUID | :ballot_box_with_check:&nbsp;1.33+ | | 1.32 | 1.33 | | | | [code](https://cs.k8s.io/?q=%5CbRemoteRequestHeaderUID%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbRemoteRequestHeaderUID%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| ResilientWatchCacheInitialization | :ballot_box_with_check:&nbsp;1.31+ | :closed_lock_with_key:&nbsp;1.34+ | | 1.311.33 | 1.34 | | | [code](https://cs.k8s.io/?q=%5CbResilientWatchCacheInitialization%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbResilientWatchCacheInitialization%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| ResourceHealthStatus | :ballot_box_with_check:&nbsp;1.36+ | | 1.311.35 | 1.36 | | | DynamicResourceAllocation | [code](https://cs.k8s.io/?q=%5CbResourceHealthStatus%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbResourceHealthStatus%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| ResourceHealthStatusMessage | :ballot_box_with_check:&nbsp;1.36+ | | | 1.36 | | | ResourceHealthStatus | [code](https://cs.k8s.io/?q=%5CbResourceHealthStatusMessage%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbResourceHealthStatusMessage%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| RestartAllContainersOnContainerExits | :ballot_box_with_check:&nbsp;1.36+ | | 1.35 | 1.36 | | | ContainerRestartRules<br>NodeDeclaredFeatures | [code](https://cs.k8s.io/?q=%5CbRestartAllContainersOnContainerExits%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbRestartAllContainersOnContainerExits%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| RetryGenerateName | :ballot_box_with_check:&nbsp;1.31+ | :closed_lock_with_key:&nbsp;1.32+ | 1.30 | 1.31 | 1.32 | | | [code](https://cs.k8s.io/?q=%5CbRetryGenerateName%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbRetryGenerateName%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| RotateKubeletServerCertificate | :ballot_box_with_check:&nbsp;1.12+ | | 1.71.11 | 1.12 | | | | [code](https://cs.k8s.io/?q=%5CbRotateKubeletServerCertificate%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbRotateKubeletServerCertificate%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| RuntimeClassInImageCriApi | | | 1.29 | | | | | [code](https://cs.k8s.io/?q=%5CbRuntimeClassInImageCriApi%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbRuntimeClassInImageCriApi%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| SELinuxChangePolicy | :ballot_box_with_check:&nbsp;1.33+ | :closed_lock_with_key:&nbsp;1.36+ | 1.32 | 1.331.35 | 1.36 | | | [code](https://cs.k8s.io/?q=%5CbSELinuxChangePolicy%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbSELinuxChangePolicy%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
@ -201,8 +195,6 @@
| StorageVersionAPI | | | 1.20 | | | | APIServerIdentity | [code](https://cs.k8s.io/?q=%5CbStorageVersionAPI%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbStorageVersionAPI%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| StorageVersionHash | :ballot_box_with_check:&nbsp;1.15+ | | 1.14 | 1.15 | | | | [code](https://cs.k8s.io/?q=%5CbStorageVersionHash%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbStorageVersionHash%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| StorageVersionMigrator | | | 1.301.34 | 1.35 | | | | [code](https://cs.k8s.io/?q=%5CbStorageVersionMigrator%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbStorageVersionMigrator%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| StreamingCollectionEncodingToJSON | :ballot_box_with_check:&nbsp;1.33+ | :closed_lock_with_key:&nbsp;1.34+ | | 1.33 | 1.34 | | | [code](https://cs.k8s.io/?q=%5CbStreamingCollectionEncodingToJSON%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbStreamingCollectionEncodingToJSON%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| StreamingCollectionEncodingToProtobuf | :ballot_box_with_check:&nbsp;1.33+ | :closed_lock_with_key:&nbsp;1.34+ | | 1.33 | 1.34 | | | [code](https://cs.k8s.io/?q=%5CbStreamingCollectionEncodingToProtobuf%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbStreamingCollectionEncodingToProtobuf%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| StrictIPCIDRValidation | :ballot_box_with_check:&nbsp;1.36+ | | 1.331.35 | 1.36 | | | | [code](https://cs.k8s.io/?q=%5CbStrictIPCIDRValidation%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbStrictIPCIDRValidation%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| StructuredAuthenticationConfigurationEgressSelector | :ballot_box_with_check:&nbsp;1.34+ | | | 1.34 | | | | [code](https://cs.k8s.io/?q=%5CbStructuredAuthenticationConfigurationEgressSelector%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbStructuredAuthenticationConfigurationEgressSelector%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |
| StructuredAuthenticationConfigurationJWKSMetrics | :ballot_box_with_check:&nbsp;1.35+ | | | 1.35 | | | | [code](https://cs.k8s.io/?q=%5CbStructuredAuthenticationConfigurationJWKSMetrics%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/kubernetes) [KEPs](https://cs.k8s.io/?q=%5CbStructuredAuthenticationConfigurationJWKSMetrics%5Cb&i=nope&files=&excludeFiles=CHANGELOG&repos=kubernetes/enhancements) |

View file

@ -87,20 +87,6 @@
lockToDefault: false
preRelease: Beta
version: "1.26"
- name: APIServerTracing
versionedSpecs:
- default: false
lockToDefault: false
preRelease: Alpha
version: "1.22"
- default: true
lockToDefault: false
preRelease: Beta
version: "1.27"
- default: true
lockToDefault: true
preRelease: GA
version: "1.34"
- name: APIServingWithRoutine
versionedSpecs:
- default: false
@ -113,16 +99,6 @@
lockToDefault: false
preRelease: Beta
version: "1.35"
- name: BtreeWatchCache
versionedSpecs:
- default: true
lockToDefault: false
preRelease: Beta
version: "1.32"
- default: true
lockToDefault: true
preRelease: GA
version: "1.33"
- name: CBORServingAndStorage
versionedSpecs:
- default: false
@ -207,20 +183,6 @@
lockToDefault: false
preRelease: Beta
version: "1.31"
- name: ConsistentListFromCache
versionedSpecs:
- default: false
lockToDefault: false
preRelease: Alpha
version: "1.28"
- default: true
lockToDefault: false
preRelease: Beta
version: "1.31"
- default: true
lockToDefault: true
preRelease: GA
version: "1.34"
- name: ConsistentListFromCacheSkipTimeoutFallback
versionedSpecs:
- default: false
@ -1281,20 +1243,6 @@
lockToDefault: false
preRelease: Beta
version: "1.35"
- name: OrderedNamespaceDeletion
versionedSpecs:
- default: false
lockToDefault: false
preRelease: Beta
version: "1.30"
- default: true
lockToDefault: false
preRelease: Beta
version: "1.33"
- default: true
lockToDefault: true
preRelease: GA
version: "1.34"
- name: PersistentVolumeClaimUnusedSinceTime
versionedSpecs:
- default: false
@ -1585,16 +1533,6 @@
lockToDefault: false
preRelease: Beta
version: "1.33"
- name: ResilientWatchCacheInitialization
versionedSpecs:
- default: true
lockToDefault: false
preRelease: Beta
version: "1.31"
- default: true
lockToDefault: true
preRelease: GA
version: "1.34"
- name: ResourceHealthStatus
versionedSpecs:
- default: false
@ -1621,20 +1559,6 @@
lockToDefault: false
preRelease: Beta
version: "1.36"
- name: RetryGenerateName
versionedSpecs:
- default: false
lockToDefault: false
preRelease: Alpha
version: "1.30"
- default: true
lockToDefault: false
preRelease: Beta
version: "1.31"
- default: true
lockToDefault: true
preRelease: GA
version: "1.32"
- name: RotateKubeletServerCertificate
versionedSpecs:
- default: false
@ -1899,26 +1823,6 @@
lockToDefault: false
preRelease: Beta
version: "1.35"
- name: StreamingCollectionEncodingToJSON
versionedSpecs:
- default: true
lockToDefault: false
preRelease: Beta
version: "1.33"
- default: true
lockToDefault: true
preRelease: GA
version: "1.34"
- name: StreamingCollectionEncodingToProtobuf
versionedSpecs:
- default: true
lockToDefault: false
preRelease: Beta
version: "1.33"
- default: true
lockToDefault: true
preRelease: GA
version: "1.34"
- name: StrictIPCIDRValidation
versionedSpecs:
- default: false