1
0
mirror of https://github.com/rancher/steve.git synced 2025-09-05 17:30:39 +00:00

[v2.9] Virtual Resource filters (#288)

Adds logic which adds virtual fields resources. This allows these fields
to be sorted/filtered on when the SQL cache is enabled. Id and
metadata.state.name were added as the first two fields.

Co-authored-by: Michael Bolot <michael.bolot@suse.com>
This commit is contained in:
Silvio Moioli
2024-10-02 14:59:54 +02:00
committed by GitHub
parent aacb5b82de
commit dd27bd0c8d
15 changed files with 611 additions and 122 deletions

View File

@@ -41,7 +41,7 @@ import (
clientgotesting "k8s.io/client-go/testing"
)
//go:generate mockgen --build_flags=--mod=mod -package sqlproxy -destination ./proxy_mocks_test.go github.com/rancher/steve/pkg/stores/sqlproxy Cache,ClientGetter,CacheFactory,SchemaColumnSetter,RelationshipNotifier
//go:generate mockgen --build_flags=--mod=mod -package sqlproxy -destination ./proxy_mocks_test.go github.com/rancher/steve/pkg/stores/sqlproxy Cache,ClientGetter,CacheFactory,SchemaColumnSetter,RelationshipNotifier,TransformBuilder
//go:generate mockgen --build_flags=--mod=mod -package sqlproxy -destination ./sql_informer_mocks_test.go github.com/rancher/lasso/pkg/cache/sql/informer ByOptionsLister
//go:generate mockgen --build_flags=--mod=mod -package sqlproxy -destination ./dynamic_mocks_test.go k8s.io/client-go/dynamic ResourceInterface
@@ -82,9 +82,9 @@ func TestNewProxyStore(t *testing.T) {
nsSchema := baseNSSchema
scc.EXPECT().SetColumns(context.Background(), &nsSchema).Return(nil)
cg.EXPECT().TableAdminClient(nil, &nsSchema, "", &WarningBuffer{}).Return(ri, nil)
cf.EXPECT().CacheFor([][]string{{"metadata", "labels[field.cattle.io/projectId]"}}, &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(&nsSchema), false).Return(c, nil)
cf.EXPECT().CacheFor([][]string{{`id`}, {`metadata`, `state`, `name`}, {"metadata", "labels[field.cattle.io/projectId]"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(&nsSchema), false).Return(c, nil)
s, err := NewProxyStore(scc, cg, rn, cf)
s, err := NewProxyStore(scc, cg, rn, nil, cf)
assert.Nil(t, err)
assert.Equal(t, scc, s.columnSetter)
assert.Equal(t, cg, s.clientGetter)
@@ -105,7 +105,7 @@ func TestNewProxyStore(t *testing.T) {
nsSchema := baseNSSchema
scc.EXPECT().SetColumns(context.Background(), &nsSchema).Return(fmt.Errorf("error"))
s, err := NewProxyStore(scc, cg, rn, cf)
s, err := NewProxyStore(scc, cg, rn, nil, cf)
assert.Nil(t, err)
assert.Equal(t, scc, s.columnSetter)
assert.Equal(t, cg, s.clientGetter)
@@ -127,7 +127,7 @@ func TestNewProxyStore(t *testing.T) {
scc.EXPECT().SetColumns(context.Background(), &nsSchema).Return(nil)
cg.EXPECT().TableAdminClient(nil, &nsSchema, "", &WarningBuffer{}).Return(nil, fmt.Errorf("error"))
s, err := NewProxyStore(scc, cg, rn, cf)
s, err := NewProxyStore(scc, cg, rn, nil, cf)
assert.Nil(t, err)
assert.Equal(t, scc, s.columnSetter)
assert.Equal(t, cg, s.clientGetter)
@@ -149,9 +149,9 @@ func TestNewProxyStore(t *testing.T) {
nsSchema := baseNSSchema
scc.EXPECT().SetColumns(context.Background(), &nsSchema).Return(nil)
cg.EXPECT().TableAdminClient(nil, &nsSchema, "", &WarningBuffer{}).Return(ri, nil)
cf.EXPECT().CacheFor([][]string{{"metadata", "labels[field.cattle.io/projectId]"}}, &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(&nsSchema), false).Return(factory.Cache{}, fmt.Errorf("error"))
cf.EXPECT().CacheFor([][]string{{`id`}, {`metadata`, `state`, `name`}, {"metadata", "labels[field.cattle.io/projectId]"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(&nsSchema), false).Return(factory.Cache{}, fmt.Errorf("error"))
s, err := NewProxyStore(scc, cg, rn, cf)
s, err := NewProxyStore(scc, cg, rn, nil, cf)
assert.Nil(t, err)
assert.Equal(t, scc, s.columnSetter)
assert.Equal(t, cg, s.clientGetter)
@@ -181,6 +181,7 @@ func TestListByPartitions(t *testing.T) {
cf := NewMockCacheFactory(gomock.NewController(t))
ri := NewMockResourceInterface(gomock.NewController(t))
bloi := NewMockByOptionsLister(gomock.NewController(t))
tb := NewMockTransformBuilder(gomock.NewController(t))
inf := &informer.Informer{
ByOptionsLister: bloi,
}
@@ -188,9 +189,10 @@ func TestListByPartitions(t *testing.T) {
ByOptionsLister: inf,
}
s := &Store{
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
transformBuilder: tb,
}
var partitions []partition.Partition
req := &types.APIRequest{
@@ -238,7 +240,8 @@ func TestListByPartitions(t *testing.T) {
assert.Nil(t, err)
cg.EXPECT().TableAdminClient(req, schema, "", &WarningBuffer{}).Return(ri, nil)
// This tests that fields are being extracted from schema columns and the type specific fields map
cf.EXPECT().CacheFor([][]string{{"some", "field"}, {"gvk", "specific", "fields"}}, &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(schema), attributes.Namespaced(schema)).Return(c, nil)
cf.EXPECT().CacheFor([][]string{{"some", "field"}, {`id`}, {`metadata`, `state`, `name`}, {"gvk", "specific", "fields"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(schema), attributes.Namespaced(schema)).Return(c, nil)
tb.EXPECT().GetTransformFunc(attributes.GVK(schema)).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
bloi.EXPECT().ListByOptions(req.Context(), opts, partitions, req.Namespace).Return(listToReturn, len(listToReturn.Items), "", nil)
list, total, contToken, err := s.ListByPartitions(req, schema, partitions)
assert.Nil(t, err)
@@ -253,11 +256,13 @@ func TestListByPartitions(t *testing.T) {
nsi := NewMockCache(gomock.NewController(t))
cg := NewMockClientGetter(gomock.NewController(t))
cf := NewMockCacheFactory(gomock.NewController(t))
tb := NewMockTransformBuilder(gomock.NewController(t))
s := &Store{
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
transformBuilder: tb,
}
var partitions []partition.Partition
req := &types.APIRequest{
@@ -317,11 +322,13 @@ func TestListByPartitions(t *testing.T) {
nsi := NewMockCache(gomock.NewController(t))
cg := NewMockClientGetter(gomock.NewController(t))
cf := NewMockCacheFactory(gomock.NewController(t))
tb := NewMockTransformBuilder(gomock.NewController(t))
s := &Store{
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
transformBuilder: tb,
}
var partitions []partition.Partition
req := &types.APIRequest{
@@ -380,11 +387,13 @@ func TestListByPartitions(t *testing.T) {
cg := NewMockClientGetter(gomock.NewController(t))
cf := NewMockCacheFactory(gomock.NewController(t))
ri := NewMockResourceInterface(gomock.NewController(t))
tb := NewMockTransformBuilder(gomock.NewController(t))
s := &Store{
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
transformBuilder: tb,
}
var partitions []partition.Partition
req := &types.APIRequest{
@@ -432,7 +441,8 @@ func TestListByPartitions(t *testing.T) {
assert.Nil(t, err)
cg.EXPECT().TableAdminClient(req, schema, "", &WarningBuffer{}).Return(ri, nil)
// This tests that fields are being extracted from schema columns and the type specific fields map
cf.EXPECT().CacheFor([][]string{{"some", "field"}, {"gvk", "specific", "fields"}}, &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(schema), attributes.Namespaced(schema)).Return(factory.Cache{}, fmt.Errorf("error"))
tb.EXPECT().GetTransformFunc(attributes.GVK(schema)).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
cf.EXPECT().CacheFor([][]string{{"some", "field"}, {`id`}, {`metadata`, `state`, `name`}, {"gvk", "specific", "fields"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(schema), attributes.Namespaced(schema)).Return(factory.Cache{}, fmt.Errorf("error"))
_, _, _, err = s.ListByPartitions(req, schema, partitions)
assert.NotNil(t, err)
@@ -447,6 +457,7 @@ func TestListByPartitions(t *testing.T) {
cf := NewMockCacheFactory(gomock.NewController(t))
ri := NewMockResourceInterface(gomock.NewController(t))
bloi := NewMockByOptionsLister(gomock.NewController(t))
tb := NewMockTransformBuilder(gomock.NewController(t))
inf := &informer.Informer{
ByOptionsLister: bloi,
}
@@ -454,9 +465,10 @@ func TestListByPartitions(t *testing.T) {
ByOptionsLister: inf,
}
s := &Store{
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
transformBuilder: tb,
}
var partitions []partition.Partition
req := &types.APIRequest{
@@ -504,8 +516,9 @@ func TestListByPartitions(t *testing.T) {
assert.Nil(t, err)
cg.EXPECT().TableAdminClient(req, schema, "", &WarningBuffer{}).Return(ri, nil)
// This tests that fields are being extracted from schema columns and the type specific fields map
cf.EXPECT().CacheFor([][]string{{"some", "field"}, {"gvk", "specific", "fields"}}, &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(schema), attributes.Namespaced(schema)).Return(c, nil)
cf.EXPECT().CacheFor([][]string{{"some", "field"}, {`id`}, {`metadata`, `state`, `name`}, {"gvk", "specific", "fields"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(schema), attributes.Namespaced(schema)).Return(c, nil)
bloi.EXPECT().ListByOptions(req.Context(), opts, partitions, req.Namespace).Return(nil, 0, "", fmt.Errorf("error"))
tb.EXPECT().GetTransformFunc(attributes.GVK(schema)).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
_, _, _, err = s.ListByPartitions(req, schema, partitions)
assert.NotNil(t, err)
@@ -531,19 +544,22 @@ func TestReset(t *testing.T) {
cf := NewMockCacheFactory(gomock.NewController(t))
cs := NewMockSchemaColumnSetter(gomock.NewController(t))
ri := NewMockResourceInterface(gomock.NewController(t))
tb := NewMockTransformBuilder(gomock.NewController(t))
nsc2 := factory.Cache{}
s := &Store{
namespaceCache: nsc,
clientGetter: cg,
cacheFactory: cf,
columnSetter: cs,
cfInitializer: func() (CacheFactory, error) { return cf, nil },
namespaceCache: nsc,
clientGetter: cg,
cacheFactory: cf,
columnSetter: cs,
cfInitializer: func() (CacheFactory, error) { return cf, nil },
transformBuilder: tb,
}
nsSchema := baseNSSchema
cf.EXPECT().Reset().Return(nil)
cs.EXPECT().SetColumns(gomock.Any(), gomock.Any()).Return(nil)
cg.EXPECT().TableAdminClient(nil, &nsSchema, "", &WarningBuffer{}).Return(ri, nil)
cf.EXPECT().CacheFor([][]string{{"metadata", "labels[field.cattle.io/projectId]"}}, &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(&nsSchema), false).Return(nsc2, nil)
cf.EXPECT().CacheFor([][]string{{`id`}, {`metadata`, `state`, `name`}, {"metadata", "labels[field.cattle.io/projectId]"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(&nsSchema), false).Return(nsc2, nil)
tb.EXPECT().GetTransformFunc(attributes.GVK(&nsSchema)).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
err := s.Reset()
assert.Nil(t, err)
assert.Equal(t, nsc2, s.namespaceCache)
@@ -556,13 +572,15 @@ func TestReset(t *testing.T) {
cg := NewMockClientGetter(gomock.NewController(t))
cf := NewMockCacheFactory(gomock.NewController(t))
cs := NewMockSchemaColumnSetter(gomock.NewController(t))
tb := NewMockTransformBuilder(gomock.NewController(t))
s := &Store{
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
columnSetter: cs,
cfInitializer: func() (CacheFactory, error) { return cf, nil },
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
columnSetter: cs,
cfInitializer: func() (CacheFactory, error) { return cf, nil },
transformBuilder: tb,
}
cf.EXPECT().Reset().Return(fmt.Errorf("error"))
@@ -577,13 +595,15 @@ func TestReset(t *testing.T) {
cg := NewMockClientGetter(gomock.NewController(t))
cf := NewMockCacheFactory(gomock.NewController(t))
cs := NewMockSchemaColumnSetter(gomock.NewController(t))
tb := NewMockTransformBuilder(gomock.NewController(t))
s := &Store{
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
columnSetter: cs,
cfInitializer: func() (CacheFactory, error) { return cf, nil },
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
columnSetter: cs,
cfInitializer: func() (CacheFactory, error) { return cf, nil },
transformBuilder: tb,
}
cf.EXPECT().Reset().Return(nil)
@@ -599,13 +619,15 @@ func TestReset(t *testing.T) {
cg := NewMockClientGetter(gomock.NewController(t))
cf := NewMockCacheFactory(gomock.NewController(t))
cs := NewMockSchemaColumnSetter(gomock.NewController(t))
tb := NewMockTransformBuilder(gomock.NewController(t))
s := &Store{
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
columnSetter: cs,
cfInitializer: func() (CacheFactory, error) { return cf, nil },
namespaceCache: nsi,
clientGetter: cg,
cacheFactory: cf,
columnSetter: cs,
cfInitializer: func() (CacheFactory, error) { return cf, nil },
transformBuilder: tb,
}
nsSchema := baseNSSchema
@@ -624,20 +646,23 @@ func TestReset(t *testing.T) {
cf := NewMockCacheFactory(gomock.NewController(t))
cs := NewMockSchemaColumnSetter(gomock.NewController(t))
ri := NewMockResourceInterface(gomock.NewController(t))
tb := NewMockTransformBuilder(gomock.NewController(t))
s := &Store{
namespaceCache: nsc,
clientGetter: cg,
cacheFactory: cf,
columnSetter: cs,
cfInitializer: func() (CacheFactory, error) { return cf, nil },
namespaceCache: nsc,
clientGetter: cg,
cacheFactory: cf,
columnSetter: cs,
cfInitializer: func() (CacheFactory, error) { return cf, nil },
transformBuilder: tb,
}
nsSchema := baseNSSchema
cf.EXPECT().Reset().Return(nil)
cs.EXPECT().SetColumns(gomock.Any(), gomock.Any()).Return(nil)
cg.EXPECT().TableAdminClient(nil, &nsSchema, "", &WarningBuffer{}).Return(ri, nil)
cf.EXPECT().CacheFor([][]string{{"metadata", "labels[field.cattle.io/projectId]"}}, &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(&nsSchema), false).Return(factory.Cache{}, fmt.Errorf("error"))
cf.EXPECT().CacheFor([][]string{{`id`}, {`metadata`, `state`, `name`}, {"metadata", "labels[field.cattle.io/projectId]"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(&nsSchema), false).Return(factory.Cache{}, fmt.Errorf("error"))
tb.EXPECT().GetTransformFunc(attributes.GVK(&nsSchema)).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
err := s.Reset()
assert.NotNil(t, err)
},