Merge pull request #121906 from ahutsunshine/namespace-indexer
support namespace indexer for namespaced resources like pods Kubernetes-commit: 2eb2a62e154d806af59cae9084e3846e7fc215d5
This commit is contained in:
commit
6e1838f4b1
4
go.mod
4
go.mod
|
|
@ -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
4
go.sum
|
|
@ -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=
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue