1
0
mirror of https://github.com/rancher/steve.git synced 2025-09-01 23:47:50 +00:00

#48673 - Added Timestamp Cache Handling to metadata.fields (#648)

* added timestamp convertion to metadata.fields

* fixed duration parsing

* fixed tests

* removed tags file

* added comments

* added better error handling

* changed ParseHumanDuration to use Fscanf

* added builtins handling

* adding mock updates

* fixing tests

* another try

* added timestamp convertion to metadata.fields

* addressing comments from @ericpromislow

* converting error to warning

* added template options
This commit is contained in:
Felipe Gehrke
2025-06-16 19:33:28 -03:00
committed by GitHub
parent 2e8a0f2851
commit b3539616e0
13 changed files with 513 additions and 33 deletions

View File

@@ -14,6 +14,7 @@ import (
reflect "reflect"
types "github.com/rancher/apiserver/pkg/types"
common "github.com/rancher/steve/pkg/resources/common"
factory "github.com/rancher/steve/pkg/sqlcache/informer/factory"
partition "github.com/rancher/steve/pkg/sqlcache/partition"
sqltypes "github.com/rancher/steve/pkg/sqlcache/sqltypes"
@@ -389,15 +390,15 @@ func (m *MockTransformBuilder) EXPECT() *MockTransformBuilderMockRecorder {
}
// GetTransformFunc mocks base method.
func (m *MockTransformBuilder) GetTransformFunc(arg0 schema.GroupVersionKind) cache.TransformFunc {
func (m *MockTransformBuilder) GetTransformFunc(arg0 schema.GroupVersionKind, arg1 []common.ColumnDefinition) cache.TransformFunc {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetTransformFunc", arg0)
ret := m.ctrl.Call(m, "GetTransformFunc", arg0, arg1)
ret0, _ := ret[0].(cache.TransformFunc)
return ret0
}
// GetTransformFunc indicates an expected call of GetTransformFunc.
func (mr *MockTransformBuilderMockRecorder) GetTransformFunc(arg0 any) *gomock.Call {
func (mr *MockTransformBuilderMockRecorder) GetTransformFunc(arg0, arg1 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransformFunc", reflect.TypeOf((*MockTransformBuilder)(nil).GetTransformFunc), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetTransformFunc", reflect.TypeOf((*MockTransformBuilder)(nil).GetTransformFunc), arg0, arg1)
}

View File

@@ -240,7 +240,7 @@ type RelationshipNotifier interface {
}
type TransformBuilder interface {
GetTransformFunc(gvk schema.GroupVersionKind) cache.TransformFunc
GetTransformFunc(gvk schema.GroupVersionKind, colDefs []common.ColumnDefinition) cache.TransformFunc
}
type Store struct {
@@ -335,9 +335,10 @@ func (s *Store) initializeNamespaceCache() error {
// get any type-specific fields that steve is interested in
fields = append(fields, getFieldForGVK(gvk)...)
cols := common.GetColumnDefinitions(&nsSchema)
// get the type-specific transform func
transformFunc := s.transformBuilder.GetTransformFunc(gvk)
transformFunc := s.transformBuilder.GetTransformFunc(gvk, cols)
// get the ns informer
tableClient := &tablelistconvert.Client{ResourceInterface: client}
@@ -545,7 +546,7 @@ func (s *Store) watch(apiOp *types.APIRequest, schema *types.APISchema, w types.
gvk := attributes.GVK(schema)
fields := getFieldsFromSchema(schema)
fields = append(fields, getFieldForGVK(gvk)...)
transformFunc := s.transformBuilder.GetTransformFunc(gvk)
transformFunc := s.transformBuilder.GetTransformFunc(gvk, nil)
tableClient := &tablelistconvert.Client{ResourceInterface: client}
attrs := attributes.GVK(schema)
ns := attributes.Namespaced(schema)
@@ -756,7 +757,9 @@ func (s *Store) ListByPartitions(apiOp *types.APIRequest, apiSchema *types.APISc
gvk := attributes.GVK(apiSchema)
fields := getFieldsFromSchema(apiSchema)
fields = append(fields, getFieldForGVK(gvk)...)
transformFunc := s.transformBuilder.GetTransformFunc(gvk)
cols := common.GetColumnDefinitions(apiSchema)
transformFunc := s.transformBuilder.GetTransformFunc(gvk, cols)
tableClient := &tablelistconvert.Client{ResourceInterface: client}
attrs := attributes.GVK(apiSchema)
ns := attributes.Namespaced(apiSchema)

View File

@@ -245,7 +245,7 @@ func TestListByPartitions(t *testing.T) {
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(context.Background(), [][]string{{"some", "field"}, {`id`}, {`metadata`, `state`, `name`}, {"gvk", "specific", "fields"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(schema), attributes.Namespaced(schema), true).Return(c, nil)
tb.EXPECT().GetTransformFunc(attributes.GVK(schema)).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
tb.EXPECT().GetTransformFunc(attributes.GVK(schema), []common.ColumnDefinition{{Field: "some.field"}}).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)
@@ -462,7 +462,7 @@ func TestListByPartitions(t *testing.T) {
// note also the watchable bool is expected to be false
cf.EXPECT().CacheFor(context.Background(), [][]string{{"some", "field"}, {`id`}, {`metadata`, `state`, `name`}, {"gvk", "specific", "fields"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(schema), attributes.Namespaced(schema), false).Return(c, nil)
tb.EXPECT().GetTransformFunc(attributes.GVK(schema)).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
tb.EXPECT().GetTransformFunc(attributes.GVK(schema), []common.ColumnDefinition{{Field: "some.field"}}).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)
@@ -534,7 +534,7 @@ 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
tb.EXPECT().GetTransformFunc(attributes.GVK(schema)).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
tb.EXPECT().GetTransformFunc(attributes.GVK(schema), gomock.Any()).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
cf.EXPECT().CacheFor(context.Background(), [][]string{{"some", "field"}, {`id`}, {`metadata`, `state`, `name`}, {"gvk", "specific", "fields"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(schema), attributes.Namespaced(schema), true).Return(factory.Cache{}, fmt.Errorf("error"))
_, _, _, err = s.ListByPartitions(req, schema, partitions)
@@ -613,7 +613,7 @@ func TestListByPartitions(t *testing.T) {
// This tests that fields are being extracted from schema columns and the type specific fields map
cf.EXPECT().CacheFor(context.Background(), [][]string{{"some", "field"}, {`id`}, {`metadata`, `state`, `name`}, {"gvk", "specific", "fields"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(schema), attributes.Namespaced(schema), true).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 })
tb.EXPECT().GetTransformFunc(attributes.GVK(schema), gomock.Any()).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
_, _, _, err = s.ListByPartitions(req, schema, partitions)
assert.NotNil(t, err)
@@ -725,7 +725,7 @@ func TestListByPartitionWithUserAccess(t *testing.T) {
attributes.SetGVK(theSchema, gvk)
cg.EXPECT().TableAdminClient(apiOp, theSchema, "", &WarningBuffer{}).Return(ri, nil)
cf.EXPECT().CacheFor(context.Background(), [][]string{{"some", "field"}, {"id"}, {"metadata", "state", "name"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(theSchema), attributes.Namespaced(theSchema), true).Return(c, nil)
tb.EXPECT().GetTransformFunc(attributes.GVK(theSchema)).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
tb.EXPECT().GetTransformFunc(attributes.GVK(theSchema), gomock.Any()).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
listToReturn := &unstructured.UnstructuredList{
Items: make([]unstructured.Unstructured, 0, 0),
@@ -767,7 +767,7 @@ func TestReset(t *testing.T) {
cs.EXPECT().SetColumns(gomock.Any(), gomock.Any()).Return(nil)
cg.EXPECT().TableAdminClient(nil, &nsSchema, "", &WarningBuffer{}).Return(ri, nil)
cf.EXPECT().CacheFor(context.Background(), [][]string{{`id`}, {`metadata`, `state`, `name`}, {"metadata", "labels", "field.cattle.io/projectId"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(&nsSchema), false, true).Return(nsc2, nil)
tb.EXPECT().GetTransformFunc(attributes.GVK(&nsSchema)).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
tb.EXPECT().GetTransformFunc(attributes.GVK(&nsSchema), gomock.Any()).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
err := s.Reset()
assert.Nil(t, err)
assert.Equal(t, nsc2, s.namespaceCache)
@@ -874,7 +874,7 @@ func TestReset(t *testing.T) {
cs.EXPECT().SetColumns(gomock.Any(), gomock.Any()).Return(nil)
cg.EXPECT().TableAdminClient(nil, &nsSchema, "", &WarningBuffer{}).Return(ri, nil)
cf.EXPECT().CacheFor(context.Background(), [][]string{{`id`}, {`metadata`, `state`, `name`}, {"metadata", "labels", "field.cattle.io/projectId"}}, gomock.Any(), &tablelistconvert.Client{ResourceInterface: ri}, attributes.GVK(&nsSchema), false, true).Return(factory.Cache{}, fmt.Errorf("error"))
tb.EXPECT().GetTransformFunc(attributes.GVK(&nsSchema)).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
tb.EXPECT().GetTransformFunc(attributes.GVK(&nsSchema), gomock.Any()).Return(func(obj interface{}) (interface{}, error) { return obj, nil })
err := s.Reset()
assert.NotNil(t, err)
},