mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
K8s/Storage: Register field-selector on all kinds (#79822)
Co-authored-by: Dan Cech <dcech@grafana.com>
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/dashboards"
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/grafana-apiserver/endpoints/request"
|
||||
"github.com/grafana/grafana/pkg/services/grafana-apiserver/storage/entity"
|
||||
"github.com/grafana/grafana/pkg/services/grafana-apiserver/utils"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
@@ -65,6 +66,17 @@ func (s *legacyStorage) List(ctx context.Context, options *internalversion.ListO
|
||||
return nil, err
|
||||
}
|
||||
|
||||
parentUID := ""
|
||||
fieldRequirements, fieldSelector, err := entity.ReadFieldRequirements(options.FieldSelector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if fieldRequirements.Folder != nil {
|
||||
parentUID = *fieldRequirements.Folder
|
||||
}
|
||||
// Update the field selector to remove the unneeded selectors
|
||||
options.FieldSelector = fieldSelector
|
||||
|
||||
paging, err := readContinueToken(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -77,6 +89,7 @@ func (s *legacyStorage) List(ctx context.Context, options *internalversion.ListO
|
||||
|
||||
// When nested folders are not enabled, all folders are root folders
|
||||
hits, err := s.service.GetChildren(ctx, &folder.GetChildrenQuery{
|
||||
UID: parentUID, // NOTE! we should do a different query when nested folders are enabled!
|
||||
SignedInUser: user,
|
||||
Limit: paging.page,
|
||||
OrgID: orgId,
|
||||
|
@@ -2,7 +2,6 @@ package playlist
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
@@ -68,28 +67,6 @@ func (b *PlaylistAPIBuilder) InstallSchema(scheme *runtime.Scheme) error {
|
||||
Version: runtime.APIVersionInternal,
|
||||
})
|
||||
|
||||
gvk := playlist.PlaylistResourceInfo.GroupVersionKind()
|
||||
|
||||
// Add playlist thing
|
||||
_ = scheme.AddFieldLabelConversionFunc(gvk,
|
||||
runtime.FieldLabelConversionFunc(
|
||||
func(label, value string) (string, string, error) {
|
||||
if strings.HasPrefix(label, "grafana.app/") {
|
||||
return label, value, nil
|
||||
}
|
||||
|
||||
switch label {
|
||||
case "metadata.name":
|
||||
return label, value, nil
|
||||
case "metadata.namespace":
|
||||
return label, value, nil
|
||||
default:
|
||||
return "", "", fmt.Errorf("%q is not a known field selector: only %q, %q", label, "metadata.name", "metadata.namespace")
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
// If multiple versions exist, then register conversions from zz_generated.conversion.go
|
||||
// if err := playlist.RegisterConversions(scheme); err != nil {
|
||||
// return err
|
||||
|
@@ -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 {
|
||||
|
Reference in New Issue
Block a user