mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 11:50:44 +00:00
Protect remainingItemCount behind a feature flag. Also updating the API doc
This commit is contained in:
parent
9577cbfb9f
commit
1ad5cb5bb1
@ -82,11 +82,18 @@ type ListMeta struct {
|
||||
// message.
|
||||
Continue string `json:"continue,omitempty" protobuf:"bytes,3,opt,name=continue"`
|
||||
|
||||
// RemainingItemCount is the number of subsequent items in the list which are not included in this
|
||||
// remainingItemCount is the number of subsequent items in the list which are not included in this
|
||||
// list response. If the list request contained label or field selectors, then the number of
|
||||
// remaining items is unknown and this field will be unset. If the list is complete (either
|
||||
// because it is unpaginated or because this is the last page), then there are no more remaining
|
||||
// items and this field will also be unset. Servers older than v1.15 do not set this field.
|
||||
// remaining items is unknown and the field will be left unset and omitted during serialization.
|
||||
// If the list is complete (either because it is not chunking or because this is the last chunk),
|
||||
// then there are no more remaining items and this field will be left unset and omitted during
|
||||
// serialization.
|
||||
// Servers older than v1.15 do not set this field.
|
||||
// The intended use of the remainingItemCount is *estimating* the size of a collection. Clients
|
||||
// should not rely on the remainingItemCount to be set or to be exact.
|
||||
//
|
||||
// This field is alpha and can be changed or removed without notice.
|
||||
//
|
||||
// +optional
|
||||
RemainingItemCount *int64 `json:"remainingItemCount,omitempty" protobuf:"bytes,4,opt,name=remainingItemCount"`
|
||||
}
|
||||
|
@ -86,6 +86,13 @@ const (
|
||||
// committing.
|
||||
DryRun featuregate.Feature = "DryRun"
|
||||
|
||||
// owner: @caesarxuchao
|
||||
// alpha: v1.15
|
||||
//
|
||||
// Allow apiservers to show a count of remaining items in the response
|
||||
// to a chunking list request.
|
||||
RemainingItemCount featuregate.Feature = "RemainingItemCount"
|
||||
|
||||
// owner: @apelisse, @lavalamp
|
||||
// alpha: v1.14
|
||||
//
|
||||
@ -140,6 +147,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
||||
APIResponseCompression: {Default: false, PreRelease: featuregate.Alpha},
|
||||
APIListChunking: {Default: true, PreRelease: featuregate.Beta},
|
||||
DryRun: {Default: true, PreRelease: featuregate.Beta},
|
||||
RemainingItemCount: {Default: false, PreRelease: featuregate.Alpha},
|
||||
ServerSideApply: {Default: false, PreRelease: featuregate.Alpha},
|
||||
StorageVersionHash: {Default: false, PreRelease: featuregate.Alpha},
|
||||
WinOverlay: {Default: false, PreRelease: featuregate.Alpha},
|
||||
|
@ -36,10 +36,12 @@ import (
|
||||
"k8s.io/apimachinery/pkg/conversion"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
"k8s.io/apiserver/pkg/storage/etcd"
|
||||
"k8s.io/apiserver/pkg/storage/etcd/metrics"
|
||||
"k8s.io/apiserver/pkg/storage/value"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
utiltrace "k8s.io/utils/trace"
|
||||
)
|
||||
|
||||
@ -622,9 +624,11 @@ func (s *store) List(ctx context.Context, key, resourceVersion string, pred stor
|
||||
// getResp.Count counts in objects that do not match the pred.
|
||||
// Instead of returning inaccurate count for non-empty selectors, we return nil.
|
||||
// Only set remainingItemCount if the predicate is empty.
|
||||
if pred.Empty() {
|
||||
c := int64(getResp.Count - pred.Limit)
|
||||
remainingItemCount = &c
|
||||
if utilfeature.DefaultFeatureGate.Enabled(features.RemainingItemCount) {
|
||||
if pred.Empty() {
|
||||
c := int64(getResp.Count - pred.Limit)
|
||||
remainingItemCount = &c
|
||||
}
|
||||
}
|
||||
return s.versioner.UpdateList(listObj, uint64(returnedRV), next, remainingItemCount)
|
||||
}
|
||||
|
@ -43,10 +43,13 @@ import (
|
||||
"k8s.io/apimachinery/pkg/watch"
|
||||
"k8s.io/apiserver/pkg/apis/example"
|
||||
examplev1 "k8s.io/apiserver/pkg/apis/example/v1"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/storage"
|
||||
"k8s.io/apiserver/pkg/storage/etcd"
|
||||
storagetests "k8s.io/apiserver/pkg/storage/tests"
|
||||
"k8s.io/apiserver/pkg/storage/value"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
)
|
||||
|
||||
@ -751,6 +754,7 @@ func TestTransformationFailure(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestList(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.RemainingItemCount, true)()
|
||||
codec := apitesting.TestCodec(codecs, examplev1.SchemeGroupVersion)
|
||||
cluster := integration.NewClusterV3(t, &integration.ClusterConfig{Size: 1})
|
||||
defer cluster.Terminate(t)
|
||||
|
@ -30,12 +30,18 @@ import (
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
"k8s.io/apiserver/pkg/features"
|
||||
"k8s.io/apiserver/pkg/storage/storagebackend"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
"k8s.io/kubernetes/test/e2e/framework"
|
||||
e2elog "k8s.io/kubernetes/test/e2e/framework/log"
|
||||
)
|
||||
|
||||
func shouldCheckRemainingItem() bool {
|
||||
return utilfeature.DefaultFeatureGate.Enabled(features.RemainingItemCount)
|
||||
}
|
||||
|
||||
const numberOfTotalResources = 400
|
||||
|
||||
var _ = SIGDescribe("Servers with support for API chunking", func() {
|
||||
@ -89,11 +95,13 @@ var _ = SIGDescribe("Servers with support for API chunking", func() {
|
||||
lastRV = list.ResourceVersion
|
||||
}
|
||||
gomega.Expect(list.ResourceVersion).To(gomega.Equal(lastRV))
|
||||
if list.GetContinue() == "" {
|
||||
gomega.Expect(list.GetRemainingItemCount()).To(gomega.BeNil())
|
||||
} else {
|
||||
gomega.Expect(list.GetRemainingItemCount()).ToNot(gomega.BeNil())
|
||||
gomega.Expect(int(*list.GetRemainingItemCount()) + len(list.Items) + found).To(gomega.BeNumerically("==", numberOfTotalResources))
|
||||
if shouldCheckRemainingItem() {
|
||||
if list.GetContinue() == "" {
|
||||
gomega.Expect(list.GetRemainingItemCount()).To(gomega.BeNil())
|
||||
} else {
|
||||
gomega.Expect(list.GetRemainingItemCount()).ToNot(gomega.BeNil())
|
||||
gomega.Expect(int(*list.GetRemainingItemCount()) + len(list.Items) + found).To(gomega.BeNumerically("==", numberOfTotalResources))
|
||||
}
|
||||
}
|
||||
for _, item := range list.Items {
|
||||
gomega.Expect(item.Name).To(gomega.Equal(fmt.Sprintf("template-%04d", found)))
|
||||
@ -127,11 +135,13 @@ var _ = SIGDescribe("Servers with support for API chunking", func() {
|
||||
framework.ExpectNoError(err, "failed to list pod templates in namespace: %s, given limit: %d", ns, opts.Limit)
|
||||
firstToken := list.Continue
|
||||
firstRV := list.ResourceVersion
|
||||
if list.GetContinue() == "" {
|
||||
gomega.Expect(list.GetRemainingItemCount()).To(gomega.BeNil())
|
||||
} else {
|
||||
gomega.Expect(list.GetRemainingItemCount()).ToNot(gomega.BeNil())
|
||||
gomega.Expect(int(*list.GetRemainingItemCount()) + len(list.Items)).To(gomega.BeNumerically("==", numberOfTotalResources))
|
||||
if shouldCheckRemainingItem() {
|
||||
if list.GetContinue() == "" {
|
||||
gomega.Expect(list.GetRemainingItemCount()).To(gomega.BeNil())
|
||||
} else {
|
||||
gomega.Expect(list.GetRemainingItemCount()).ToNot(gomega.BeNil())
|
||||
gomega.Expect(int(*list.GetRemainingItemCount()) + len(list.Items)).To(gomega.BeNumerically("==", numberOfTotalResources))
|
||||
}
|
||||
}
|
||||
e2elog.Logf("Retrieved %d/%d results with rv %s and continue %s", len(list.Items), opts.Limit, list.ResourceVersion, firstToken)
|
||||
|
||||
@ -167,11 +177,14 @@ var _ = SIGDescribe("Servers with support for API chunking", func() {
|
||||
gomega.Expect(list.ResourceVersion).ToNot(gomega.Equal(firstRV))
|
||||
gomega.Expect(len(list.Items)).To(gomega.BeNumerically("==", opts.Limit))
|
||||
found := int(oneTenth)
|
||||
if list.GetContinue() == "" {
|
||||
gomega.Expect(list.GetRemainingItemCount()).To(gomega.BeNil())
|
||||
} else {
|
||||
gomega.Expect(list.GetRemainingItemCount()).ToNot(gomega.BeNil())
|
||||
gomega.Expect(int(*list.GetRemainingItemCount()) + len(list.Items) + found).To(gomega.BeNumerically("==", numberOfTotalResources))
|
||||
|
||||
if shouldCheckRemainingItem() {
|
||||
if list.GetContinue() == "" {
|
||||
gomega.Expect(list.GetRemainingItemCount()).To(gomega.BeNil())
|
||||
} else {
|
||||
gomega.Expect(list.GetRemainingItemCount()).ToNot(gomega.BeNil())
|
||||
gomega.Expect(int(*list.GetRemainingItemCount()) + len(list.Items) + found).To(gomega.BeNumerically("==", numberOfTotalResources))
|
||||
}
|
||||
}
|
||||
for _, item := range list.Items {
|
||||
gomega.Expect(item.Name).To(gomega.Equal(fmt.Sprintf("template-%04d", found)))
|
||||
@ -184,11 +197,13 @@ var _ = SIGDescribe("Servers with support for API chunking", func() {
|
||||
for {
|
||||
list, err := client.List(opts)
|
||||
framework.ExpectNoError(err, "failed to list pod templates in namespace: %s, given limit: %d", ns, opts.Limit)
|
||||
if list.GetContinue() == "" {
|
||||
gomega.Expect(list.GetRemainingItemCount()).To(gomega.BeNil())
|
||||
} else {
|
||||
gomega.Expect(list.GetRemainingItemCount()).ToNot(gomega.BeNil())
|
||||
gomega.Expect(int(*list.GetRemainingItemCount()) + len(list.Items) + found).To(gomega.BeNumerically("==", numberOfTotalResources))
|
||||
if shouldCheckRemainingItem() {
|
||||
if list.GetContinue() == "" {
|
||||
gomega.Expect(list.GetRemainingItemCount()).To(gomega.BeNil())
|
||||
} else {
|
||||
gomega.Expect(list.GetRemainingItemCount()).ToNot(gomega.BeNil())
|
||||
gomega.Expect(int(*list.GetRemainingItemCount()) + len(list.Items) + found).To(gomega.BeNumerically("==", numberOfTotalResources))
|
||||
}
|
||||
}
|
||||
e2elog.Logf("Retrieved %d/%d results with rv %s and continue %s", len(list.Items), opts.Limit, list.ResourceVersion, list.Continue)
|
||||
gomega.Expect(len(list.Items)).To(gomega.BeNumerically("<=", opts.Limit))
|
||||
|
Loading…
Reference in New Issue
Block a user