Merge pull request #121906 from ahutsunshine/namespace-indexer

support namespace indexer for namespaced resources like pods

Kubernetes-commit: 2eb2a62e154d806af59cae9084e3846e7fc215d5
This commit is contained in:
Kubernetes Publisher 2023-12-13 23:55:46 +01:00
commit 6e1838f4b1
5 changed files with 101 additions and 7 deletions

4
go.mod
View File

@ -43,7 +43,7 @@ require (
gopkg.in/natefinch/lumberjack.v2 v2.2.1 gopkg.in/natefinch/lumberjack.v2 v2.2.1
gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/square/go-jose.v2 v2.6.0
k8s.io/api v0.0.0-20231214011710-3da949756c6e k8s.io/api v0.0.0-20231214011710-3da949756c6e
k8s.io/apimachinery v0.0.0-20231214011457-aa9a6c8873ce k8s.io/apimachinery v0.0.0-20231214011457-e2f405af78de
k8s.io/client-go v0.0.0-20231214012015-feecac4b447f k8s.io/client-go v0.0.0-20231214012015-feecac4b447f
k8s.io/component-base v0.0.0-20231214012652-f2e48902f05e k8s.io/component-base v0.0.0-20231214012652-f2e48902f05e
k8s.io/klog/v2 v2.110.1 k8s.io/klog/v2 v2.110.1
@ -127,7 +127,7 @@ require (
replace ( replace (
k8s.io/api => k8s.io/api v0.0.0-20231214011710-3da949756c6e k8s.io/api => k8s.io/api v0.0.0-20231214011710-3da949756c6e
k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20231214011457-2341c262cb7a k8s.io/apimachinery => k8s.io/apimachinery v0.0.0-20231214011457-e2f405af78de
k8s.io/client-go => k8s.io/client-go v0.0.0-20231214012015-feecac4b447f k8s.io/client-go => k8s.io/client-go v0.0.0-20231214012015-feecac4b447f
k8s.io/component-base => k8s.io/component-base v0.0.0-20231214012652-f2e48902f05e k8s.io/component-base => k8s.io/component-base v0.0.0-20231214012652-f2e48902f05e
k8s.io/kms => k8s.io/kms v0.0.0-20231113172825-1bfdb22033cb k8s.io/kms => k8s.io/kms v0.0.0-20231113172825-1bfdb22033cb

4
go.sum
View File

@ -399,8 +399,8 @@ honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
k8s.io/api v0.0.0-20231214011710-3da949756c6e h1:fb5/DSwCxilOSn7b1YGyne+Zy6VLNZ9HFmUtST/Pi6c= k8s.io/api v0.0.0-20231214011710-3da949756c6e h1:fb5/DSwCxilOSn7b1YGyne+Zy6VLNZ9HFmUtST/Pi6c=
k8s.io/api v0.0.0-20231214011710-3da949756c6e/go.mod h1:eV1U/hIzpNFn8BwKNS23N26x5/161bpaa6+1UCZ36wI= k8s.io/api v0.0.0-20231214011710-3da949756c6e/go.mod h1:eV1U/hIzpNFn8BwKNS23N26x5/161bpaa6+1UCZ36wI=
k8s.io/apimachinery v0.0.0-20231214011457-2341c262cb7a h1:lbvobsLJdsboCR4h+BTUlqbPTOGLjTAXjYIRlrmZ/As= k8s.io/apimachinery v0.0.0-20231214011457-e2f405af78de h1:gOF2Xlsae9C8Cp7Te7Pxw2D0i4m8ddqrsX8lAvfsOrE=
k8s.io/apimachinery v0.0.0-20231214011457-2341c262cb7a/go.mod h1:djf1C8dGXS7Htg00o2kMGnUD7h6rmK/5k36U8AzZRSw= k8s.io/apimachinery v0.0.0-20231214011457-e2f405af78de/go.mod h1:djf1C8dGXS7Htg00o2kMGnUD7h6rmK/5k36U8AzZRSw=
k8s.io/client-go v0.0.0-20231214012015-feecac4b447f h1:Hod+TPK99qpPFOKNv5ac6Z1huXBZLWd+EcFnjUWOym0= k8s.io/client-go v0.0.0-20231214012015-feecac4b447f h1:Hod+TPK99qpPFOKNv5ac6Z1huXBZLWd+EcFnjUWOym0=
k8s.io/client-go v0.0.0-20231214012015-feecac4b447f/go.mod h1:cj2m+csCOBfKj4ShaVpDGi3DVcZpFd2uqRbVETSvegs= k8s.io/client-go v0.0.0-20231214012015-feecac4b447f/go.mod h1:cj2m+csCOBfKj4ShaVpDGi3DVcZpFd2uqRbVETSvegs=
k8s.io/component-base v0.0.0-20231214012652-f2e48902f05e h1:2I18e1Yvhzg5RfEJr5V9BBw67TgdMAUzU6rzv4e4AXk= k8s.io/component-base v0.0.0-20231214012652-f2e48902f05e h1:2I18e1Yvhzg5RfEJr5V9BBw67TgdMAUzU6rzv4e4AXk=

View File

@ -746,7 +746,7 @@ func (c *Cacher) listItems(ctx context.Context, listRV uint64, key string, pred
} }
return nil, readResourceVersion, "", nil 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 // GetList implements storage.Interface

View File

@ -17,10 +17,13 @@ limitations under the License.
package storage package storage
import ( import (
"context"
"k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/api/meta"
"k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "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. // 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) // For any index defined by IndexFields, if a matcher can match only (a subset)
// of objects that return <value> for a given index, a pair (<index name>, <value>) // of objects that return <value> for a given index, a pair (<index name>, <value>)
// wil be returned. // wil be returned.
func (s *SelectionPredicate) MatcherIndex() []MatchValue { func (s *SelectionPredicate) MatcherIndex(ctx context.Context) []MatchValue {
var result []MatchValue var result []MatchValue
for _, field := range s.IndexFields { for _, field := range s.IndexFields {
if value, ok := s.Field.RequiresExactMatch(field); ok { if value, ok := s.Field.RequiresExactMatch(field); ok {
result = append(result, MatchValue{IndexName: FieldIndex(field), Value: value}) 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 { for _, label := range s.IndexLabels {
@ -160,6 +168,14 @@ func (s *SelectionPredicate) MatcherIndex() []MatchValue {
return result 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. // LabelIndex add prefix for label index.
func LabelIndex(label string) string { func LabelIndex(label string) string {
return "l:" + label return "l:" + label

View File

@ -17,6 +17,7 @@ limitations under the License.
package storage package storage
import ( import (
"context"
"errors" "errors"
"reflect" "reflect"
"testing" "testing"
@ -25,6 +26,7 @@ import (
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apiserver/pkg/endpoints/request"
) )
type Ignored struct { type Ignored struct {
@ -127,12 +129,14 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) {
indexLabels []string indexLabels []string
indexFields []string indexFields []string
expected []MatchValue expected []MatchValue
ctx context.Context
}{ }{
"Match nil": { "Match nil": {
labelSelector: "name=foo", labelSelector: "name=foo",
fieldSelector: "uid=12345", fieldSelector: "uid=12345",
indexLabels: []string{"bar"}, indexLabels: []string{"bar"},
indexFields: []string{}, indexFields: []string{},
ctx: context.Background(),
expected: nil, expected: nil,
}, },
"Match field": { "Match field": {
@ -140,13 +144,83 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) {
fieldSelector: "uid=12345", fieldSelector: "uid=12345",
indexLabels: []string{}, indexLabels: []string{},
indexFields: []string{"uid"}, indexFields: []string{"uid"},
ctx: context.Background(),
expected: []MatchValue{{IndexName: FieldIndex("uid"), Value: "12345"}}, 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": { "Match label": {
labelSelector: "name=foo", labelSelector: "name=foo",
fieldSelector: "uid=12345", fieldSelector: "uid=12345",
indexLabels: []string{"name"}, indexLabels: []string{"name"},
indexFields: []string{}, indexFields: []string{},
ctx: context.Background(),
expected: []MatchValue{{IndexName: LabelIndex("name"), Value: "foo"}}, expected: []MatchValue{{IndexName: LabelIndex("name"), Value: "foo"}},
}, },
"Match field and label": { "Match field and label": {
@ -154,6 +228,7 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) {
fieldSelector: "uid=12345", fieldSelector: "uid=12345",
indexLabels: []string{"name"}, indexLabels: []string{"name"},
indexFields: []string{"uid"}, indexFields: []string{"uid"},
ctx: context.Background(),
expected: []MatchValue{{IndexName: FieldIndex("uid"), Value: "12345"}, {IndexName: LabelIndex("name"), Value: "foo"}}, expected: []MatchValue{{IndexName: FieldIndex("uid"), Value: "12345"}, {IndexName: LabelIndex("name"), Value: "foo"}},
}, },
"Negative match field and label": { "Negative match field and label": {
@ -161,6 +236,7 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) {
fieldSelector: "uid!=12345", fieldSelector: "uid!=12345",
indexLabels: []string{"name"}, indexLabels: []string{"name"},
indexFields: []string{"uid"}, indexFields: []string{"uid"},
ctx: context.Background(),
expected: nil, expected: nil,
}, },
"Negative match field and match label": { "Negative match field and match label": {
@ -168,6 +244,7 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) {
fieldSelector: "uid!=12345", fieldSelector: "uid!=12345",
indexLabels: []string{"name"}, indexLabels: []string{"name"},
indexFields: []string{"uid"}, indexFields: []string{"uid"},
ctx: context.Background(),
expected: []MatchValue{{IndexName: LabelIndex("name"), Value: "foo"}}, expected: []MatchValue{{IndexName: LabelIndex("name"), Value: "foo"}},
}, },
"Negative match label and match field": { "Negative match label and match field": {
@ -175,6 +252,7 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) {
fieldSelector: "uid=12345", fieldSelector: "uid=12345",
indexLabels: []string{"name"}, indexLabels: []string{"name"},
indexFields: []string{"uid"}, indexFields: []string{"uid"},
ctx: context.Background(),
expected: []MatchValue{{IndexName: FieldIndex("uid"), Value: "12345"}}, expected: []MatchValue{{IndexName: FieldIndex("uid"), Value: "12345"}},
}, },
} }
@ -194,7 +272,7 @@ func TestSelectionPredicateMatcherIndex(t *testing.T) {
IndexLabels: testCase.indexLabels, IndexLabels: testCase.indexLabels,
IndexFields: testCase.indexFields, IndexFields: testCase.indexFields,
} }
actual := sp.MatcherIndex() actual := sp.MatcherIndex(testCase.ctx)
if !reflect.DeepEqual(testCase.expected, actual) { if !reflect.DeepEqual(testCase.expected, actual) {
t.Errorf("%v: expected %v, got %v", name, testCase.expected, actual) t.Errorf("%v: expected %v, got %v", name, testCase.expected, actual)
} }