K8s: Folders: Modify GetChildren to return only Folder References (#103072)

* Return FolderReference instead of Folder on GetChildren

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

---------

Signed-off-by: Maicon Costa <maiconscosta@gmail.com>
This commit is contained in:
maicon
2025-04-02 01:30:17 -03:00
committed by GitHub
parent 654afbcfa2
commit d8c5c2d3b8
24 changed files with 107 additions and 104 deletions
+20 -15
View File
@@ -385,14 +385,14 @@ func (s *Service) setFullpath(ctx context.Context, f *folder.Folder, user identi
return f, nil
}
func (s *Service) GetChildren(ctx context.Context, q *folder.GetChildrenQuery) ([]*folder.Folder, error) {
func (s *Service) GetChildren(ctx context.Context, q *folder.GetChildrenQuery) ([]*folder.FolderReference, error) {
if s.features.IsEnabledGlobally(featuremgmt.FlagKubernetesClientDashboardsFolders) {
return s.getChildrenFromApiServer(ctx, q)
}
return s.GetChildrenLegacy(ctx, q)
}
func (s *Service) GetChildrenLegacy(ctx context.Context, q *folder.GetChildrenQuery) ([]*folder.Folder, error) {
func (s *Service) GetChildrenLegacy(ctx context.Context, q *folder.GetChildrenQuery) ([]*folder.FolderReference, error) {
defer func(t time.Time) {
parent := q.UID
if q.UID != folder.SharedWithMeFolderUID {
@@ -465,7 +465,7 @@ func (s *Service) GetChildrenLegacy(ctx context.Context, q *folder.GetChildrenQu
return children, nil
}
func (s *Service) getRootFolders(ctx context.Context, q *folder.GetChildrenQuery) ([]*folder.Folder, error) {
func (s *Service) getRootFolders(ctx context.Context, q *folder.GetChildrenQuery) ([]*folder.FolderReference, error) {
permissions := q.SignedInUser.GetPermissions()
var folderPermissions []string
if q.Permission == dashboardaccess.PERMISSION_EDIT {
@@ -513,7 +513,7 @@ func (s *Service) getRootFolders(ctx context.Context, q *folder.GetChildrenQuery
// fetch folder from dashboard store
dashFolder, ok := dashFolders[f.UID]
if !ok {
s.log.Error("failed to fetch folder by UID from dashboard store", "orgID", f.OrgID, "uid", f.UID)
s.log.Error("failed to fetch folder by UID from dashboard store", "orgID", q.OrgID, "uid", f.UID)
}
// always expose the dashboard store sequential ID
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.Folder).Inc()
@@ -527,21 +527,21 @@ func (s *Service) getRootFolders(ctx context.Context, q *folder.GetChildrenQuery
// add "shared with me" folder on the 1st page
if (q.Page == 0 || q.Page == 1) && len(q.FolderUIDs) != 0 {
children = append([]*folder.Folder{&folder.SharedWithMeFolder}, children...)
children = append([]*folder.FolderReference{folder.SharedWithMeFolder.ToFolderReference()}, children...)
}
return children, nil
}
// GetSharedWithMe returns folders available to user, which cannot be accessed from the root folders
func (s *Service) GetSharedWithMe(ctx context.Context, q *folder.GetChildrenQuery, forceLegacy bool) ([]*folder.Folder, error) {
func (s *Service) GetSharedWithMe(ctx context.Context, q *folder.GetChildrenQuery, forceLegacy bool) ([]*folder.FolderReference, error) {
start := time.Now()
availableNonRootFolders, err := s.getAvailableNonRootFolders(ctx, q, forceLegacy)
if err != nil {
s.metrics.sharedWithMeFetchFoldersRequestsDuration.WithLabelValues("failure").Observe(time.Since(start).Seconds())
return nil, folder.ErrInternal.Errorf("failed to fetch subfolders to which the user has explicit access: %w", err)
}
var rootFolders []*folder.Folder
var rootFolders []*folder.FolderReference
if forceLegacy {
rootFolders, err = s.GetChildrenLegacy(ctx, &folder.GetChildrenQuery{UID: "", OrgID: q.OrgID, SignedInUser: q.SignedInUser, Permission: q.Permission})
} else {
@@ -552,9 +552,9 @@ func (s *Service) GetSharedWithMe(ctx context.Context, q *folder.GetChildrenQuer
return nil, folder.ErrInternal.Errorf("failed to fetch root folders to which the user has access: %w", err)
}
availableNonRootFolders = s.deduplicateAvailableFolders(ctx, availableNonRootFolders, rootFolders, q.OrgID)
dedupAvailableNonRootFolders := s.deduplicateAvailableFolders(ctx, availableNonRootFolders, rootFolders, q.OrgID)
s.metrics.sharedWithMeFetchFoldersRequestsDuration.WithLabelValues("success").Observe(time.Since(start).Seconds())
return availableNonRootFolders, nil
return dedupAvailableNonRootFolders, nil
}
func (s *Service) getAvailableNonRootFolders(ctx context.Context, q *folder.GetChildrenQuery, forceLegacy bool) ([]*folder.Folder, error) {
@@ -618,12 +618,17 @@ func (s *Service) getAvailableNonRootFolders(ctx context.Context, q *folder.GetC
return nonRootFolders, nil
}
func (s *Service) deduplicateAvailableFolders(ctx context.Context, folders []*folder.Folder, rootFolders []*folder.Folder, orgID int64) []*folder.Folder {
allFolders := append(folders, rootFolders...)
foldersDedup := make([]*folder.Folder, 0)
func (s *Service) deduplicateAvailableFolders(ctx context.Context, folders []*folder.Folder, rootFolders []*folder.FolderReference, orgID int64) []*folder.FolderReference {
foldersRef := make([]*folder.FolderReference, len(folders))
for i, f := range folders {
foldersRef[i] = f.ToFolderReference()
}
allFolders := append(foldersRef, rootFolders...)
foldersDedup := make([]*folder.FolderReference, 0)
for _, f := range folders {
isSubfolder := slices.ContainsFunc(allFolders, func(folder *folder.Folder) bool {
isSubfolder := slices.ContainsFunc(allFolders, func(folder *folder.FolderReference) bool {
return f.ParentUID == folder.UID
})
@@ -638,7 +643,7 @@ func (s *Service) deduplicateAvailableFolders(ctx context.Context, folders []*fo
}
for _, parentUID := range parentUIDs {
contains := slices.ContainsFunc(allFolders, func(f *folder.Folder) bool {
contains := slices.ContainsFunc(allFolders, func(f *folder.FolderReference) bool {
return f.UID == parentUID
})
if contains {
@@ -649,7 +654,7 @@ func (s *Service) deduplicateAvailableFolders(ctx context.Context, folders []*fo
}
if !isSubfolder {
foldersDedup = append(foldersDedup, f)
foldersDedup = append(foldersDedup, f.ToFolderReference())
}
}
return foldersDedup
@@ -343,7 +343,7 @@ func (s *Service) getFolderByTitleFromApiServer(ctx context.Context, orgID int64
return f, nil
}
func (s *Service) getChildrenFromApiServer(ctx context.Context, q *folder.GetChildrenQuery) ([]*folder.Folder, error) {
func (s *Service) getChildrenFromApiServer(ctx context.Context, q *folder.GetChildrenQuery) ([]*folder.FolderReference, error) {
defer func(t time.Time) {
parent := q.UID
if q.UID != folder.SharedWithMeFolderUID {
@@ -397,7 +397,7 @@ func (s *Service) getChildrenFromApiServer(ctx context.Context, q *folder.GetChi
return children, nil
}
func (s *Service) getRootFoldersFromApiServer(ctx context.Context, q *folder.GetChildrenQuery) ([]*folder.Folder, error) {
func (s *Service) getRootFoldersFromApiServer(ctx context.Context, q *folder.GetChildrenQuery) ([]*folder.FolderReference, error) {
permissions := q.SignedInUser.GetPermissions()
var folderPermissions []string
if q.Permission == dashboardaccess.PERMISSION_EDIT {
@@ -432,7 +432,7 @@ func (s *Service) getRootFoldersFromApiServer(ctx context.Context, q *folder.Get
// add "shared with me" folder on the 1st page
if (q.Page == 0 || q.Page == 1) && len(q.FolderUIDs) != 0 {
children = append([]*folder.Folder{&folder.SharedWithMeFolder}, children...)
children = append([]*folder.FolderReference{folder.SharedWithMeFolder.ToFolderReference()}, children...)
}
return children, nil
+2 -8
View File
@@ -321,8 +321,8 @@ func (ss *FolderStoreImpl) GetParents(ctx context.Context, q folder.GetParentsQu
return util.Reverse(folders[1:]), nil
}
func (ss *FolderStoreImpl) GetChildren(ctx context.Context, q folder.GetChildrenQuery) ([]*folder.Folder, error) {
var folders []*folder.Folder
func (ss *FolderStoreImpl) GetChildren(ctx context.Context, q folder.GetChildrenQuery) ([]*folder.FolderReference, error) {
var folders []*folder.FolderReference
err := ss.db.WithDbSession(ctx, func(sess *db.Session) error {
sql := strings.Builder{}
@@ -368,12 +368,6 @@ func (ss *FolderStoreImpl) GetChildren(ctx context.Context, q folder.GetChildren
return folder.ErrDatabaseError.Errorf("failed to get folder children: %w", err)
}
if err := concurrency.ForEachJob(ctx, len(folders), runtime.NumCPU(), func(ctx context.Context, idx int) error {
folders[idx].WithURL()
return nil
}); err != nil {
ss.log.Debug("failed to set URL to folders", "err", err)
}
return nil
})
return folders, err
@@ -633,7 +633,6 @@ func TestIntegrationGetChildren(t *testing.T) {
childrenUIDs := make([]string, 0, len(children))
for _, c := range children {
assert.NotEmpty(t, c.URL)
childrenUIDs = append(childrenUIDs, c.UID)
}
@@ -650,7 +649,6 @@ func TestIntegrationGetChildren(t *testing.T) {
childrenUIDs := make([]string, 0, len(children))
for _, c := range children {
assert.NotEmpty(t, c.URL)
childrenUIDs = append(childrenUIDs, c.UID)
}
assert.Equal(t, []string{parent.UID}, childrenUIDs)
@@ -683,7 +681,6 @@ func TestIntegrationGetChildren(t *testing.T) {
childrenUIDs = make([]string, 0, len(children))
for _, c := range children {
assert.NotEmpty(t, c.URL)
childrenUIDs = append(childrenUIDs, c.UID)
}
@@ -701,7 +698,6 @@ func TestIntegrationGetChildren(t *testing.T) {
childrenUIDs = make([]string, 0, len(children))
for _, c := range children {
assert.NotEmpty(t, c.URL)
childrenUIDs = append(childrenUIDs, c.UID)
}
@@ -721,7 +717,6 @@ func TestIntegrationGetChildren(t *testing.T) {
childrenUIDs = make([]string, 0, len(children))
for _, c := range children {
assert.NotEmpty(t, c.URL)
childrenUIDs = append(childrenUIDs, c.UID)
}
@@ -739,7 +734,6 @@ func TestIntegrationGetChildren(t *testing.T) {
childrenUIDs = make([]string, 0, len(children))
for _, c := range children {
assert.NotEmpty(t, c.URL)
childrenUIDs = append(childrenUIDs, c.UID)
}
@@ -757,7 +751,6 @@ func TestIntegrationGetChildren(t *testing.T) {
childrenUIDs = make([]string, 0, len(children))
for _, c := range children {
assert.NotEmpty(t, c.URL)
childrenUIDs = append(childrenUIDs, c.UID)
}
+9 -23
View File
@@ -171,7 +171,7 @@ func (ss *FolderUnifiedStoreImpl) GetParents(ctx context.Context, q folder.GetPa
return hits, nil
}
func (ss *FolderUnifiedStoreImpl) GetChildren(ctx context.Context, q folder.GetChildrenQuery) ([]*folder.Folder, error) {
func (ss *FolderUnifiedStoreImpl) GetChildren(ctx context.Context, q folder.GetChildrenQuery) ([]*folder.FolderReference, error) {
// the general folder is saved as an empty string in the database
if q.UID == folder.GeneralFolderUID {
q.UID = ""
@@ -230,36 +230,22 @@ func (ss *FolderUnifiedStoreImpl) GetChildren(ctx context.Context, q folder.GetC
}
allowK6Folder := (q.SignedInUser != nil && q.SignedInUser.IsIdentityType(claims.TypeServiceAccount))
hits := make([]*folder.Folder, 0)
hits := make([]*folder.FolderReference, 0)
for _, item := range res.Hits {
// filter out k6 folders if request is not from a service account
if item.Name == accesscontrol.K6FolderUID && !allowK6Folder {
continue
}
// TODO: Remove this once we migrate the alerting use case.
// This is a temporary flag, and will be removed once we migrate the alerting use case to
// expect a folder ref too for children folders.
if q.RefOnly { // nolint:staticcheck
f := &folder.Folder{
ID: item.Field.GetNestedInt64(search.DASHBOARD_LEGACY_ID),
UID: item.Name,
Title: item.Title,
ParentUID: item.Folder,
}
if item.Field.GetNestedString(resource.SEARCH_FIELD_MANAGER_KIND) != "" {
f.ManagedBy = utils.ParseManagerKindString(item.Field.GetNestedString(resource.SEARCH_FIELD_MANAGER_KIND))
}
hits = append(hits, f)
continue
f := &folder.FolderReference{
ID: item.Field.GetNestedInt64(search.DASHBOARD_LEGACY_ID),
UID: item.Name,
Title: item.Title,
ParentUID: item.Folder,
}
// search only returns a subset of info, get all info of the folder
f, err := ss.Get(ctx, folder.GetFolderQuery{UID: &item.Name, OrgID: q.OrgID})
if err != nil {
return nil, err
if item.Field.GetNestedString(resource.SEARCH_FIELD_MANAGER_KIND) != "" {
f.ManagedBy = utils.ParseManagerKindString(item.Field.GetNestedString(resource.SEARCH_FIELD_MANAGER_KIND))
}
hits = append(hits, f)
@@ -430,9 +430,8 @@ func TestGetChildren(t *testing.T) {
// don't set page or limit - should be automatically added
result, err := store.GetChildren(ctx, folder.GetChildrenQuery{
UID: "folder1",
OrgID: orgID,
RefOnly: true, // nolint:staticcheck
UID: "folder1",
OrgID: orgID,
})
require.NoError(t, err)
require.Len(t, result, 2)