K8s/Storage: Register field-selector on all kinds (#79822)

Co-authored-by: Dan Cech <dcech@grafana.com>
This commit is contained in:
Ryan McKinley
2024-01-16 08:30:01 -08:00
committed by GitHub
co-authored by Dan Cech
parent 73715a1de9
commit e1d387d826
5 changed files with 102 additions and 43 deletions
@@ -324,6 +324,12 @@ func (s *service) start(ctx context.Context) error {
return err
}
// support folder selection
err = entitystorage.RegisterFieldSelectorSupport(Scheme)
if err != nil {
return err
}
// Create the server
server, err := serverConfig.Complete().New("grafana-apiserver", genericapiserver.NewEmptyDelegate())
if err != nil {
@@ -0,0 +1,76 @@
package entity
import (
"fmt"
"strings"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/fields"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/selection"
)
const folderAnnoKey = "grafana.app/folder"
type FieldRequirements struct {
// Equals folder
Folder *string
}
func ReadFieldRequirements(selector fields.Selector) (FieldRequirements, fields.Selector, error) {
requirements := FieldRequirements{}
if selector == nil {
return requirements, selector, nil
}
for _, r := range selector.Requirements() {
switch r.Field {
case folderAnnoKey:
if (r.Operator != selection.Equals) && (r.Operator != selection.DoubleEquals) {
return requirements, selector, apierrors.NewBadRequest("only equality is supported in the selectors")
}
folder := r.Value
requirements.Folder = &folder
}
}
// use Transform function to remove grafana.app/folder field selector
selector, err := selector.Transform(func(field, value string) (string, string, error) {
switch field {
case folderAnnoKey:
return "", "", nil
}
return field, value, nil
})
return requirements, selector, err
}
func RegisterFieldSelectorSupport(scheme *runtime.Scheme) error {
grafanaFieldSupport := runtime.FieldLabelConversionFunc(
func(field, value string) (string, string, error) {
if strings.HasPrefix(field, "grafana.app/") {
return field, value, nil
}
return "", "", getBadSelectorError(field)
},
)
// Register all the internal types
for gvk := range scheme.AllKnownTypes() {
if strings.HasSuffix(gvk.Group, ".grafana.app") {
err := scheme.AddFieldLabelConversionFunc(gvk, grafanaFieldSupport)
if err != nil {
return err
}
}
}
return nil
}
func getBadSelectorError(f string) error {
return apierrors.NewBadRequest(
fmt.Sprintf("%q is not a known field selector: only %q works", f, folderAnnoKey),
)
}
@@ -241,29 +241,16 @@ func (s *Storage) GetList(ctx context.Context, key string, opts storage.ListOpti
}
}
// translate grafana.app/folder field selector to folder condition
fields := opts.Predicate.Field.Requirements()
for _, f := range fields {
if f.Field == "grafana.app/folder" {
if f.Operator != selection.Equals {
return apierrors.NewBadRequest("grafana.app/folder field selector only supports equality")
}
// select items in the spcified folder
req.Folder = f.Value
}
}
// use Transform function to remove grafana.app/folder field selector
opts.Predicate.Field, err = opts.Predicate.Field.Transform(func(field, value string) (string, string, error) {
if field == "grafana.app/folder" {
return "", "", nil
}
return field, value, nil
})
// translate grafana.app/folder field selector to the folder condition
fieldRequirements, fieldSelector, err := ReadFieldRequirements(opts.Predicate.Field)
if err != nil {
return err
}
if fieldRequirements.Folder != nil {
req.Folder = *fieldRequirements.Folder
}
// Update the field selector to remove the unneeded selectors
opts.Predicate.Field = fieldSelector
rsp, err := s.store.List(ctx, req)
if err != nil {