From 16536b9b6315426495fe80427876170e34af043c Mon Sep 17 00:00:00 2001 From: ahutsunshine Date: Wed, 29 Nov 2023 15:51:24 +0800 Subject: [PATCH] support pod namespace indexer fix comments optimize code small optimization for the namespace scope check Kubernetes-commit: d8bd150784bb4825ae891dd0ec84625bdba0f2b8 --- pkg/storage/cacher/cacher.go | 2 +- pkg/storage/selection_predicate.go | 18 +++++- pkg/storage/selection_predicate_test.go | 80 ++++++++++++++++++++++++- 3 files changed, 97 insertions(+), 3 deletions(-) diff --git a/pkg/storage/cacher/cacher.go b/pkg/storage/cacher/cacher.go index 4f4080441..3778a83c0 100644 --- a/pkg/storage/cacher/cacher.go +++ b/pkg/storage/cacher/cacher.go @@ -746,7 +746,7 @@ func (c *Cacher) listItems(ctx context.Context, listRV uint64, key string, pred } return nil, readResourceVersion, "", nil } - return c.watchCache.WaitUntilFreshAndList(ctx, listRV, pred.MatcherIndex()) + return c.watchCache.WaitUntilFreshAndList(ctx, listRV, pred.MatcherIndex(ctx)) } // GetList implements storage.Interface diff --git a/pkg/storage/selection_predicate.go b/pkg/storage/selection_predicate.go index a0a14366f..e652845c2 100644 --- a/pkg/storage/selection_predicate.go +++ b/pkg/storage/selection_predicate.go @@ -17,10 +17,13 @@ limitations under the License. package storage import ( + "context" + "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/endpoints/request" ) // AttrFunc returns label and field sets and the uninitialized flag for List or Watch to match. @@ -145,11 +148,16 @@ func (s *SelectionPredicate) Empty() bool { // For any index defined by IndexFields, if a matcher can match only (a subset) // of objects that return for a given index, a pair (, ) // wil be returned. -func (s *SelectionPredicate) MatcherIndex() []MatchValue { +func (s *SelectionPredicate) MatcherIndex(ctx context.Context) []MatchValue { var result []MatchValue for _, field := range s.IndexFields { if value, ok := s.Field.RequiresExactMatch(field); ok { result = append(result, MatchValue{IndexName: FieldIndex(field), Value: value}) + } else if field == "metadata.namespace" { + // list pods in the namespace. i.e. /api/v1/namespaces/default/pods + if namespace, isNamespaceScope := isNamespaceScopedRequest(ctx); isNamespaceScope { + result = append(result, MatchValue{IndexName: FieldIndex(field), Value: namespace}) + } } } for _, label := range s.IndexLabels { @@ -160,6 +168,14 @@ func (s *SelectionPredicate) MatcherIndex() []MatchValue { return result } +func isNamespaceScopedRequest(ctx context.Context) (string, bool) { + re, _ := request.RequestInfoFrom(ctx) + if re == nil || len(re.Namespace) == 0 { + return "", false + } + return re.Namespace, true +} + // LabelIndex add prefix for label index. func LabelIndex(label string) string { return "l:" + label diff --git a/pkg/storage/selection_predicate_test.go b/pkg/storage/selection_predicate_test.go index fc030cc99..1fc9499fa 100644 --- a/pkg/storage/selection_predicate_test.go +++ b/pkg/storage/selection_predicate_test.go @@ -17,6 +17,7 @@ limitations under the License. package storage import ( + "context" "errors" "reflect" "testing" @@ -25,6 +26,7 @@ import ( "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apiserver/pkg/endpoints/request" ) type Ignored struct { @@ -127,12 +129,14 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) { indexLabels []string indexFields []string expected []MatchValue + ctx context.Context }{ "Match nil": { labelSelector: "name=foo", fieldSelector: "uid=12345", indexLabels: []string{"bar"}, indexFields: []string{}, + ctx: context.Background(), expected: nil, }, "Match field": { @@ -140,13 +144,83 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) { fieldSelector: "uid=12345", indexLabels: []string{}, indexFields: []string{"uid"}, + ctx: context.Background(), expected: []MatchValue{{IndexName: FieldIndex("uid"), Value: "12345"}}, }, + "Match field for listing namespace pods without metadata.namespace field selector": { + labelSelector: "", + fieldSelector: "", + indexLabels: []string{}, + indexFields: []string{"metadata.namespace"}, + ctx: request.WithRequestInfo(context.Background(), &request.RequestInfo{ + IsResourceRequest: true, + Path: "/api/v1/namespaces/default/pods", + Verb: "list", + APIPrefix: "api", + APIGroup: "", + APIVersion: "v1", + Namespace: "default", + Resource: "pods", + }), + expected: []MatchValue{{IndexName: FieldIndex("metadata.namespace"), Value: "default"}}, + }, + "Match field for listing namespace pods with metadata.namespace field selector": { + labelSelector: "", + fieldSelector: "metadata.namespace=kube-system", + indexLabels: []string{}, + indexFields: []string{"metadata.namespace"}, + ctx: request.WithRequestInfo(context.Background(), &request.RequestInfo{ + IsResourceRequest: true, + Path: "/api/v1/namespaces/default/pods", + Verb: "list", + APIPrefix: "api", + APIGroup: "", + APIVersion: "v1", + Namespace: "default", + Resource: "pods", + }), + expected: []MatchValue{{IndexName: FieldIndex("metadata.namespace"), Value: "kube-system"}}, + }, + "Match field for listing all pods without metadata.namespace field selector": { + labelSelector: "", + fieldSelector: "", + indexLabels: []string{}, + indexFields: []string{"metadata.namespace"}, + ctx: request.WithRequestInfo(context.Background(), &request.RequestInfo{ + IsResourceRequest: true, + Path: "/api/v1/pods", + Verb: "list", + APIPrefix: "api", + APIGroup: "", + APIVersion: "v1", + Namespace: "", + Resource: "pods", + }), + expected: nil, + }, + "Match field for listing all pods with metadata.namespace field selector": { + labelSelector: "", + fieldSelector: "metadata.namespace=default", + indexLabels: []string{}, + indexFields: []string{"metadata.namespace"}, + ctx: request.WithRequestInfo(context.Background(), &request.RequestInfo{ + IsResourceRequest: true, + Path: "/api/v1/pods", + Verb: "list", + APIPrefix: "api", + APIGroup: "", + APIVersion: "v1", + Namespace: "default", + Resource: "pods", + }), + expected: []MatchValue{{IndexName: FieldIndex("metadata.namespace"), Value: "default"}}, + }, "Match label": { labelSelector: "name=foo", fieldSelector: "uid=12345", indexLabels: []string{"name"}, indexFields: []string{}, + ctx: context.Background(), expected: []MatchValue{{IndexName: LabelIndex("name"), Value: "foo"}}, }, "Match field and label": { @@ -154,6 +228,7 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) { fieldSelector: "uid=12345", indexLabels: []string{"name"}, indexFields: []string{"uid"}, + ctx: context.Background(), expected: []MatchValue{{IndexName: FieldIndex("uid"), Value: "12345"}, {IndexName: LabelIndex("name"), Value: "foo"}}, }, "Negative match field and label": { @@ -161,6 +236,7 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) { fieldSelector: "uid!=12345", indexLabels: []string{"name"}, indexFields: []string{"uid"}, + ctx: context.Background(), expected: nil, }, "Negative match field and match label": { @@ -168,6 +244,7 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) { fieldSelector: "uid!=12345", indexLabels: []string{"name"}, indexFields: []string{"uid"}, + ctx: context.Background(), expected: []MatchValue{{IndexName: LabelIndex("name"), Value: "foo"}}, }, "Negative match label and match field": { @@ -175,6 +252,7 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) { fieldSelector: "uid=12345", indexLabels: []string{"name"}, indexFields: []string{"uid"}, + ctx: context.Background(), expected: []MatchValue{{IndexName: FieldIndex("uid"), Value: "12345"}}, }, } @@ -194,7 +272,7 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) { IndexLabels: testCase.indexLabels, IndexFields: testCase.indexFields, } - actual := sp.MatcherIndex() + actual := sp.MatcherIndex(testCase.ctx) if !reflect.DeepEqual(testCase.expected, actual) { t.Errorf("%v: expected %v, got %v", name, testCase.expected, actual) }