Unistore: Get Folder By ID (#99131)

* Unistore: Get Folder By ID

Signed-off-by: Maicon Costa <maiconscosta@gmail.com>

---------

Signed-off-by: Maicon Costa <maiconscosta@gmail.com>
Co-authored-by: Stephanie Hingtgen <stephanie.hingtgen@grafana.com>
This commit is contained in:
maicon
2025-01-22 01:45:59 -03:00
committed by GitHub
co-authored by Stephanie Hingtgen
parent 20d25c6ad9
commit 28ad61ff6c
11 changed files with 425 additions and 187 deletions
@@ -2,6 +2,7 @@ package folderimpl
import (
"context"
"fmt"
"strings"
"time"
@@ -9,21 +10,26 @@ import (
"go.opentelemetry.io/otel/trace"
"golang.org/x/exp/slices"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/selection"
"k8s.io/client-go/dynamic"
clientrest "k8s.io/client-go/rest"
"github.com/grafana/grafana/pkg/apimachinery/identity"
"github.com/grafana/grafana/pkg/apimachinery/utils"
"github.com/grafana/grafana/pkg/apis/folder/v0alpha1"
"github.com/grafana/grafana/pkg/events"
"github.com/grafana/grafana/pkg/infra/metrics"
"github.com/grafana/grafana/pkg/services/accesscontrol"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/dashboardaccess"
dashboardsearch "github.com/grafana/grafana/pkg/services/dashboards/service/search"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/guardian"
"github.com/grafana/grafana/pkg/services/store/entity"
"github.com/grafana/grafana/pkg/setting"
"github.com/grafana/grafana/pkg/storage/unified/resource"
"github.com/grafana/grafana/pkg/util"
)
@@ -31,15 +37,17 @@ import (
type folderK8sHandler interface {
getClient(ctx context.Context, orgID int64) (dynamic.ResourceInterface, bool)
getNamespace(orgID int64) string
getSearcher(ctx context.Context) resource.ResourceClient
}
var _ folderK8sHandler = (*foldk8sHandler)(nil)
type foldk8sHandler struct {
cfg *setting.Cfg
namespacer request.NamespaceMapper
gvr schema.GroupVersionResource
restConfigProvider func(ctx context.Context) *clientrest.Config
cfg *setting.Cfg
namespacer request.NamespaceMapper
gvr schema.GroupVersionResource
restConfigProvider func(ctx context.Context) *clientrest.Config
recourceClientProvider func(ctx context.Context) resource.ResourceClient
}
func (s *Service) getFoldersFromApiServer(ctx context.Context, q folder.GetFoldersQuery) ([]*folder.Folder, error) {
@@ -93,6 +101,8 @@ func (s *Service) getFromApiServer(ctx context.Context, q *folder.GetFolderQuery
return folder.SharedWithMeFolder.WithURL(), nil
}
ctx = identity.WithRequester(ctx, q.SignedInUser)
var dashFolder *folder.Folder
var err error
switch {
@@ -102,13 +112,17 @@ func (s *Service) getFromApiServer(ctx context.Context, q *folder.GetFolderQuery
}
dashFolder, err = s.unifiedStore.Get(ctx, *q)
if err != nil {
return nil, err
return nil, toFolderError(err)
}
// nolint:staticcheck
case q.ID != nil:
// not implemented
dashFolder, err = s.getFolderByIDFromApiServer(ctx, *q.ID, q.OrgID)
if err != nil {
return nil, toFolderError(err)
}
case q.Title != nil:
// not implemented
return nil, folder.ErrBadRequest.Errorf("not implemented")
default:
return nil, folder.ErrBadRequest.Errorf("either on of UID, ID, Title fields must be present")
}
@@ -155,6 +169,61 @@ func (s *Service) getFromApiServer(ctx context.Context, q *folder.GetFolderQuery
return f, err
}
func (s *Service) getFolderByIDFromApiServer(ctx context.Context, id int64, orgID int64) (*folder.Folder, error) {
if id == 0 {
return &folder.GeneralFolder, nil
}
folderkey := &resource.ResourceKey{
Namespace: s.k8sclient.getNamespace(orgID),
Group: v0alpha1.FolderResourceInfo.GroupVersionResource().Group,
Resource: v0alpha1.FolderResourceInfo.GroupVersionResource().Resource,
}
request := &resource.ResourceSearchRequest{
Options: &resource.ListOptions{
Key: folderkey,
Fields: []*resource.Requirement{},
Labels: []*resource.Requirement{
{
Key: utils.LabelKeyDeprecatedInternalID, // nolint:staticcheck
Operator: string(selection.In),
Values: []string{fmt.Sprintf("%d", id)},
},
},
},
Limit: 100000}
client := s.k8sclient.getSearcher(ctx)
res, err := client.Search(ctx, request)
if err != nil {
return nil, err
}
hits, err := dashboardsearch.ParseResults(res, 0)
if err != nil {
return nil, err
}
if len(hits.Hits) == 0 {
return nil, dashboards.ErrFolderNotFound
}
uid := hits.Hits[0].Name
user, err := identity.GetRequester(ctx)
if err != nil {
return nil, err
}
f, err := s.Get(ctx, &folder.GetFolderQuery{UID: &uid, SignedInUser: user, OrgID: orgID})
if err != nil {
return nil, err
}
return f, nil
}
func (s *Service) getChildrenFromApiServer(ctx context.Context, q *folder.GetChildrenQuery) ([]*folder.Folder, error) {
defer func(t time.Time) {
parent := q.UID
@@ -697,3 +766,7 @@ func (fk8s *foldk8sHandler) getClient(ctx context.Context, orgID int64) (dynamic
func (fk8s *foldk8sHandler) getNamespace(orgID int64) string {
return fk8s.namespacer(orgID)
}
func (fk8s *foldk8sHandler) getSearcher(ctx context.Context) resource.ResourceClient {
return fk8s.recourceClientProvider(ctx)
}