diff --git a/pkg/registry/generic/registry/store.go b/pkg/registry/generic/registry/store.go index b5705f6fd..be51729f5 100644 --- a/pkg/registry/generic/registry/store.go +++ b/pkg/registry/generic/registry/store.go @@ -1267,8 +1267,23 @@ func (e *Store) CompleteWithOptions(options *generic.StoreOptions) error { if options.RESTOptions == nil { return fmt.Errorf("options for %s must have RESTOptions set", e.QualifiedResource.String()) } - if options.AttrFunc == nil { - return fmt.Errorf("options for %s must have AttrFunc set", e.QualifiedResource.String()) + + attrFunc := options.AttrFunc + if attrFunc == nil { + if isNamespaced { + attrFunc = storage.DefaultNamespaceScopedAttr + } else { + attrFunc = storage.DefaultClusterScopedAttr + } + } + if e.PredicateFunc == nil { + e.PredicateFunc = func(label labels.Selector, field fields.Selector) storage.SelectionPredicate { + return storage.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: attrFunc, + } + } } opts, err := options.RESTOptions.GetRESTOptions(e.QualifiedResource) @@ -1349,7 +1364,7 @@ func (e *Store) CompleteWithOptions(options *generic.StoreOptions) error { prefix, keyFunc, e.NewListFunc, - options.AttrFunc, + attrFunc, triggerFunc, ) } diff --git a/pkg/storage/selection_predicate.go b/pkg/storage/selection_predicate.go index 95636ccd7..8421e2103 100644 --- a/pkg/storage/selection_predicate.go +++ b/pkg/storage/selection_predicate.go @@ -17,6 +17,7 @@ limitations under the License. package storage import ( + "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/runtime" @@ -26,6 +27,48 @@ import ( // In any failure to parse given object, it returns error. type AttrFunc func(obj runtime.Object) (labels.Set, fields.Set, bool, error) +// FieldMutationFunc allows the mutation of the field selection fields. It is mutating to +// avoid the extra allocation on this common path +type FieldMutationFunc func(obj runtime.Object, fieldSet fields.Set) error + +func DefaultClusterScopedAttr(obj runtime.Object) (labels.Set, fields.Set, bool, error) { + metadata, err := meta.Accessor(obj) + if err != nil { + return nil, nil, false, err + } + fieldSet := fields.Set{ + "metadata.name": metadata.GetName(), + } + + return labels.Set(metadata.GetLabels()), fieldSet, metadata.GetInitializers() != nil, nil +} + +func DefaultNamespaceScopedAttr(obj runtime.Object) (labels.Set, fields.Set, bool, error) { + metadata, err := meta.Accessor(obj) + if err != nil { + return nil, nil, false, err + } + fieldSet := fields.Set{ + "metadata.name": metadata.GetName(), + "metadata.namespace": metadata.GetNamespace(), + } + + return labels.Set(metadata.GetLabels()), fieldSet, metadata.GetInitializers() != nil, nil +} + +func (f AttrFunc) WithFieldMutation(fieldMutator FieldMutationFunc) AttrFunc { + return func(obj runtime.Object) (labels.Set, fields.Set, bool, error) { + labelSet, fieldSet, initialized, err := f(obj) + if err != nil { + return nil, nil, false, err + } + if err := fieldMutator(obj, fieldSet); err != nil { + return nil, nil, false, err + } + return labelSet, fieldSet, initialized, nil + } +} + // SelectionPredicate is used to represent the way to select objects from api storage. type SelectionPredicate struct { Label labels.Selector