Skip to content

Commit 9d2fc46

Browse files
authored
Merge pull request kubernetes#130637 from serathius/watchcache-unify-validation
Unify ListOptions validation between cache and etcd
2 parents 5227bad + ccb607f commit 9d2fc46

File tree

4 files changed

+200
-174
lines changed

4 files changed

+200
-174
lines changed

staging/src/k8s.io/apiserver/pkg/storage/etcd3/store.go

Lines changed: 2 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ import (
3333

3434
apierrors "k8s.io/apimachinery/pkg/api/errors"
3535
"k8s.io/apimachinery/pkg/api/meta"
36-
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3736
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3837
"k8s.io/apimachinery/pkg/conversion"
3938
"k8s.io/apimachinery/pkg/fields"
@@ -645,47 +644,6 @@ func (s *store) ReadinessCheck() error {
645644
return nil
646645
}
647646

648-
// resolveGetListRev is used by GetList to resolve the rev to use in the client.KV.Get request.
649-
func (s *store) resolveGetListRev(continueKey string, continueRV int64, opts storage.ListOptions) (int64, error) {
650-
var withRev int64
651-
// Uses continueRV if this is a continuation request.
652-
if len(continueKey) > 0 {
653-
if len(opts.ResourceVersion) > 0 && opts.ResourceVersion != "0" {
654-
return withRev, apierrors.NewBadRequest("specifying resource version is not allowed when using continue")
655-
}
656-
// If continueRV > 0, the LIST request needs a specific resource version.
657-
// continueRV==0 is invalid.
658-
// If continueRV < 0, the request is for the latest resource version.
659-
if continueRV > 0 {
660-
withRev = continueRV
661-
}
662-
return withRev, nil
663-
}
664-
// Returns 0 if ResourceVersion is not specified.
665-
if len(opts.ResourceVersion) == 0 {
666-
return withRev, nil
667-
}
668-
parsedRV, err := s.versioner.ParseResourceVersion(opts.ResourceVersion)
669-
if err != nil {
670-
return withRev, apierrors.NewBadRequest(fmt.Sprintf("invalid resource version: %v", err))
671-
}
672-
673-
switch opts.ResourceVersionMatch {
674-
case metav1.ResourceVersionMatchNotOlderThan:
675-
// The not older than constraint is checked after we get a response from etcd,
676-
// and returnedRV is then set to the revision we get from the etcd response.
677-
case metav1.ResourceVersionMatchExact:
678-
withRev = int64(parsedRV)
679-
case "": // legacy case
680-
if opts.Recursive && opts.Predicate.Limit > 0 && parsedRV > 0 {
681-
withRev = int64(parsedRV)
682-
}
683-
default:
684-
return withRev, fmt.Errorf("unknown ResourceVersionMatch value: %v", opts.ResourceVersionMatch)
685-
}
686-
return withRev, nil
687-
}
688-
689647
func (s *store) GetCurrentResourceVersion(ctx context.Context) (uint64, error) {
690648
emptyList := s.newListFunc()
691649
pred := storage.SelectionPredicate{
@@ -753,15 +711,8 @@ func (s *store) GetList(ctx context.Context, key string, opts storage.ListOption
753711
paging := opts.Predicate.Limit > 0
754712
newItemFunc := getNewItemFunc(listObj, v)
755713

756-
var continueRV, withRev int64
757-
var continueKey string
758-
if opts.Recursive && len(opts.Predicate.Continue) > 0 {
759-
continueKey, continueRV, err = storage.DecodeContinue(opts.Predicate.Continue, keyPrefix)
760-
if err != nil {
761-
return apierrors.NewBadRequest(fmt.Sprintf("invalid continue token: %v", err))
762-
}
763-
}
764-
if withRev, err = s.resolveGetListRev(continueKey, continueRV, opts); err != nil {
714+
withRev, continueKey, err := storage.ValidateListOptions(keyPrefix, s.versioner, opts)
715+
if err != nil {
765716
return err
766717
}
767718

staging/src/k8s.io/apiserver/pkg/storage/etcd3/store_test.go

Lines changed: 0 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -696,129 +696,6 @@ func TestInvalidKeys(t *testing.T) {
696696
expectInvalidKey("Count", countErr)
697697
}
698698

699-
func TestResolveGetListRev(t *testing.T) {
700-
_, store, _ := testSetup(t)
701-
testCases := []struct {
702-
name string
703-
continueKey string
704-
continueRV int64
705-
rv string
706-
rvMatch metav1.ResourceVersionMatch
707-
recursive bool
708-
expectedError string
709-
limit int64
710-
expectedRev int64
711-
}{
712-
{
713-
name: "specifying resource versionwhen using continue",
714-
continueKey: "continue",
715-
continueRV: 100,
716-
rv: "200",
717-
expectedError: "specifying resource version is not allowed when using continue",
718-
},
719-
{
720-
name: "invalid resource version",
721-
rv: "invalid",
722-
expectedError: "invalid resource version",
723-
},
724-
{
725-
name: "unknown ResourceVersionMatch value",
726-
rv: "200",
727-
rvMatch: "unknown",
728-
expectedError: "unknown ResourceVersionMatch value",
729-
},
730-
{
731-
name: "use continueRV",
732-
continueKey: "continue",
733-
continueRV: 100,
734-
rv: "0",
735-
expectedRev: 100,
736-
},
737-
{
738-
name: "use continueRV with empty rv",
739-
continueKey: "continue",
740-
continueRV: 100,
741-
rv: "",
742-
expectedRev: 100,
743-
},
744-
{
745-
name: "continueRV = 0",
746-
continueKey: "continue",
747-
continueRV: 0,
748-
rv: "",
749-
expectedRev: 0,
750-
},
751-
{
752-
name: "continueRV < 0",
753-
continueKey: "continue",
754-
continueRV: -1,
755-
rv: "",
756-
expectedRev: 0,
757-
},
758-
{
759-
name: "default",
760-
expectedRev: 0,
761-
},
762-
{
763-
name: "rev resolve to 0 if ResourceVersionMatchNotOlderThan",
764-
rv: "200",
765-
rvMatch: metav1.ResourceVersionMatchNotOlderThan,
766-
expectedRev: 0,
767-
},
768-
{
769-
name: "specified rev if ResourceVersionMatchExact",
770-
rv: "200",
771-
rvMatch: metav1.ResourceVersionMatchExact,
772-
expectedRev: 200,
773-
},
774-
{
775-
name: "rev resolve to 0 if not recursive",
776-
rv: "200",
777-
limit: 1,
778-
expectedRev: 0,
779-
},
780-
{
781-
name: "rev resolve to 0 if limit unspecified",
782-
rv: "200",
783-
recursive: true,
784-
expectedRev: 0,
785-
},
786-
{
787-
name: "specified rev if recursive with limit",
788-
rv: "200",
789-
recursive: true,
790-
limit: 1,
791-
expectedRev: 200,
792-
},
793-
}
794-
for _, tt := range testCases {
795-
tt := tt
796-
t.Run(tt.name, func(t *testing.T) {
797-
storageOpts := storage.ListOptions{
798-
ResourceVersion: tt.rv,
799-
ResourceVersionMatch: tt.rvMatch,
800-
Predicate: storage.SelectionPredicate{
801-
Limit: tt.limit,
802-
},
803-
Recursive: tt.recursive,
804-
}
805-
rev, err := store.resolveGetListRev(tt.continueKey, tt.continueRV, storageOpts)
806-
if len(tt.expectedError) > 0 {
807-
if err == nil || !strings.Contains(err.Error(), tt.expectedError) {
808-
t.Fatalf("expected error: %s, but got: %v", tt.expectedError, err)
809-
}
810-
return
811-
}
812-
if err != nil {
813-
t.Fatalf("resolveRevForGetList failed: %v", err)
814-
}
815-
if rev != tt.expectedRev {
816-
t.Errorf("%s: expecting rev = %d, but get %d", tt.name, tt.expectedRev, rev)
817-
}
818-
})
819-
}
820-
}
821-
822699
func BenchmarkStore_GetList(b *testing.B) {
823700
generateBigPod := func(index int, total int, expect int) runtime.Object {
824701
l := map[string]string{}

staging/src/k8s.io/apiserver/pkg/storage/interfaces.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"fmt"
2222

23+
apierrors "k8s.io/apimachinery/pkg/api/errors"
2324
"k8s.io/apimachinery/pkg/api/meta"
2425
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2526
"k8s.io/apimachinery/pkg/fields"
@@ -329,3 +330,43 @@ type DeleteOptions struct {
329330
// object which otherwise can not be deleted using the normal flow
330331
IgnoreStoreReadError bool
331332
}
333+
334+
func ValidateListOptions(keyPrefix string, versioner Versioner, opts ListOptions) (withRev int64, continueKey string, err error) {
335+
if opts.Recursive && len(opts.Predicate.Continue) > 0 {
336+
continueKey, continueRV, err := DecodeContinue(opts.Predicate.Continue, keyPrefix)
337+
if err != nil {
338+
return 0, "", apierrors.NewBadRequest(fmt.Sprintf("invalid continue token: %v", err))
339+
}
340+
if len(opts.ResourceVersion) > 0 && opts.ResourceVersion != "0" {
341+
return 0, "", apierrors.NewBadRequest("specifying resource version is not allowed when using continue")
342+
}
343+
// If continueRV > 0, the LIST request needs a specific resource version.
344+
// continueRV==0 is invalid.
345+
// If continueRV < 0, the request is for the latest resource version.
346+
if continueRV > 0 {
347+
withRev = continueRV
348+
}
349+
return withRev, continueKey, nil
350+
}
351+
if len(opts.ResourceVersion) == 0 {
352+
return withRev, "", nil
353+
}
354+
parsedRV, err := versioner.ParseResourceVersion(opts.ResourceVersion)
355+
if err != nil {
356+
return withRev, "", apierrors.NewBadRequest(fmt.Sprintf("invalid resource version: %v", err))
357+
}
358+
switch opts.ResourceVersionMatch {
359+
case metav1.ResourceVersionMatchNotOlderThan:
360+
// The not older than constraint is checked after we get a response from etcd,
361+
// and returnedRV is then set to the revision we get from the etcd response.
362+
case metav1.ResourceVersionMatchExact:
363+
withRev = int64(parsedRV)
364+
case "": // legacy case
365+
if opts.Recursive && opts.Predicate.Limit > 0 && parsedRV > 0 {
366+
withRev = int64(parsedRV)
367+
}
368+
default:
369+
return withRev, "", fmt.Errorf("unknown ResourceVersionMatch value: %v", opts.ResourceVersionMatch)
370+
}
371+
return withRev, "", nil
372+
}

0 commit comments

Comments
 (0)