Folders/K8s: Fix createdBy and updatedBy fields in response (#99569)

pull/99709/head
Arati R. 11 months ago committed by GitHub
parent d81b1bf803
commit 94a844977e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 49
      pkg/registry/apis/folders/conversions.go
  2. 104
      pkg/services/folder/folderimpl/conversions.go
  3. 18
      pkg/services/folder/folderimpl/conversions_test.go
  4. 4
      pkg/services/folder/folderimpl/folder.go
  5. 7
      pkg/services/folder/folderimpl/folder_unifiedstorage_test.go
  6. 33
      pkg/services/folder/folderimpl/unifiedstore.go

@ -6,13 +6,10 @@ import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
authlib "github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/apimachinery/utils"
"github.com/grafana/grafana/pkg/apis/folder/v0alpha1"
"github.com/grafana/grafana/pkg/infra/slugify"
"github.com/grafana/grafana/pkg/services/apiserver/endpoints/request"
gapiutil "github.com/grafana/grafana/pkg/services/apiserver/utils"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/util"
)
@ -41,52 +38,6 @@ func LegacyCreateCommandToUnstructured(cmd *folder.CreateFolderCommand) (*unstru
return obj, nil
}
func UnstructuredToLegacyFolder(item *unstructured.Unstructured) (*folder.Folder, error) {
meta, err := utils.MetaAccessor(item)
if err != nil {
return nil, err
}
info, _ := authlib.ParseNamespace(meta.GetNamespace())
if info.OrgID < 0 {
info.OrgID = 1 // This resolves all test cases that assume org 1
}
title, _, _ := unstructured.NestedString(item.Object, "spec", "title")
description, _, _ := unstructured.NestedString(item.Object, "spec", "description")
uid := meta.GetName()
url := ""
if uid != folder.RootFolder.UID {
slug := slugify.Slugify(title)
url = dashboards.GetFolderURL(uid, slug)
}
created := meta.GetCreationTimestamp().Time.UTC()
updated, _ := meta.GetUpdatedTimestamp()
if updated == nil {
updated = &created
} else {
tmp := updated.UTC()
updated = &tmp
}
return &folder.Folder{
UID: uid,
Title: title,
Description: description,
ID: meta.GetDeprecatedInternalID(), // nolint:staticcheck
ParentUID: meta.GetFolder(),
Version: int(meta.GetGeneration()),
Repository: meta.GetRepositoryName(),
URL: url,
Created: created,
Updated: *updated,
OrgID: info.OrgID,
}, nil
}
func LegacyFolderToUnstructured(v *folder.Folder, namespacer request.NamespaceMapper) (*v0alpha1.Folder, error) {
return convertToK8sResource(v, namespacer)
}

@ -0,0 +1,104 @@
package folderimpl
import (
"context"
"errors"
"strconv"
"strings"
authlib "github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/apimachinery/utils"
"github.com/grafana/grafana/pkg/infra/slugify"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/user"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
func (ss *FolderUnifiedStoreImpl) UnstructuredToLegacyFolder(ctx context.Context, item *unstructured.Unstructured) (*folder.Folder, error) {
meta, err := utils.MetaAccessor(item)
if err != nil {
return nil, err
}
info, _ := authlib.ParseNamespace(meta.GetNamespace())
if info.OrgID < 0 {
info.OrgID = 1 // This resolves all test cases that assume org 1
}
title, _, _ := unstructured.NestedString(item.Object, "spec", "title")
description, _, _ := unstructured.NestedString(item.Object, "spec", "description")
uid := meta.GetName()
url := ""
if uid != folder.RootFolder.UID {
slug := slugify.Slugify(title)
url = dashboards.GetFolderURL(uid, slug)
}
created := meta.GetCreationTimestamp().Time.UTC()
updated, _ := meta.GetUpdatedTimestamp()
if updated == nil {
updated = &created
} else {
tmp := updated.UTC()
updated = &tmp
}
creator, err := ss.getUserFromMeta(ctx, meta.GetCreatedBy())
if err != nil {
return nil, err
}
updater, err := ss.getUserFromMeta(ctx, meta.GetUpdatedBy())
if err != nil {
return nil, err
}
if updater.UID == "" {
updater = creator
}
return &folder.Folder{
UID: uid,
Title: title,
Description: description,
ID: meta.GetDeprecatedInternalID(), // nolint:staticcheck
ParentUID: meta.GetFolder(),
Version: int(meta.GetGeneration()),
Repository: meta.GetRepositoryName(),
URL: url,
Created: created,
Updated: *updated,
OrgID: info.OrgID,
CreatedBy: creator.ID,
UpdatedBy: updater.ID,
}, nil
}
func (ss *FolderUnifiedStoreImpl) getUserFromMeta(ctx context.Context, userMeta string) (*user.User, error) {
if userMeta == "" || toUID(userMeta) == "" {
return &user.User{}, nil
}
usr, err := ss.getUser(ctx, toUID(userMeta))
if err != nil && errors.Is(err, user.ErrUserNotFound) {
return &user.User{}, nil
}
return usr, err
}
func (ss *FolderUnifiedStoreImpl) getUser(ctx context.Context, uid string) (*user.User, error) {
userID, err := strconv.ParseInt(uid, 10, 64)
if err == nil {
return ss.userService.GetByID(ctx, &user.GetUserByIDQuery{ID: userID})
}
return ss.userService.GetByUID(ctx, &user.GetUserByUIDQuery{UID: uid})
}
func toUID(rawIdentifier string) string {
parts := strings.Split(rawIdentifier, ":")
if len(parts) < 2 {
return ""
}
return parts[1]
}

@ -1,6 +1,7 @@
package folders
package folderimpl
import (
"context"
"testing"
"time"
@ -8,6 +9,8 @@ import (
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/user/usertest"
)
func TestFolderConversions(t *testing.T) {
@ -29,8 +32,8 @@ func TestFolderConversions(t *testing.T) {
"grafana.app/folder": "parent-folder-name",
"grafana.app/updatedTimestamp": "2022-12-02T07:02:02Z",
"grafana.app/repoName": "example-repo",
"grafana.app/createdBy": "user:abc",
"grafana.app/updatedBy": "service:xyz"
"grafana.app/createdBy": "user:useruid",
"grafana.app/updatedBy": "user:useruid"
}
},
"spec": {
@ -44,7 +47,12 @@ func TestFolderConversions(t *testing.T) {
created = created.UTC()
require.NoError(t, err)
converted, err := UnstructuredToLegacyFolder(input)
fake := usertest.NewUserServiceFake()
fake.ExpectedUser = &user.User{ID: 10, UID: "useruid"}
fs := ProvideUnifiedStore(nil, fake)
converted, err := fs.UnstructuredToLegacyFolder(context.Background(), input)
require.NoError(t, err)
require.Equal(t, folder.Folder{
ID: 234,
@ -58,5 +66,7 @@ func TestFolderConversions(t *testing.T) {
Repository: "example-repo",
Created: created,
Updated: created.Add(time.Hour * 5),
CreatedBy: 10,
UpdatedBy: 10,
}, *converted)
}

@ -53,7 +53,6 @@ type Service struct {
log *slog.Logger
dashboardStore dashboards.Store
dashboardFolderStore folder.FolderStore
userService user.Service
features featuremgmt.FeatureToggles
accessControl accesscontrol.AccessControl
k8sclient folderK8sHandler
@ -88,7 +87,6 @@ func ProvideService(
dashboardStore: dashboardStore,
dashboardFolderStore: folderStore,
store: store,
userService: userService,
features: features,
accessControl: ac,
bus: bus,
@ -114,7 +112,7 @@ func ProvideService(
recourceClientProvider: unified.GetResourceClient,
}
unifiedStore := ProvideUnifiedStore(k8sHandler)
unifiedStore := ProvideUnifiedStore(k8sHandler, userService)
srv.unifiedStore = unifiedStore
srv.k8sclient = k8sHandler

@ -35,6 +35,7 @@ import (
"github.com/grafana/grafana/pkg/services/publicdashboards"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/services/user/usertest"
"github.com/grafana/grafana/pkg/storage/unified/resource"
)
@ -181,7 +182,11 @@ func TestIntegrationFolderServiceViaUnifiedStorage(t *testing.T) {
recourceClientProvider: f,
}
unifiedStore := ProvideUnifiedStore(k8sHandler)
userService := &usertest.FakeUserService{
ExpectedUser: &user.User{},
}
unifiedStore := ProvideUnifiedStore(k8sHandler, userService)
ctx := context.Background()
usr := &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{

@ -20,21 +20,24 @@ import (
internalfolders "github.com/grafana/grafana/pkg/registry/apis/folders"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/util"
)
type FolderUnifiedStoreImpl struct {
log log.Logger
k8sclient folderK8sHandler
log log.Logger
k8sclient folderK8sHandler
userService user.Service
}
// sqlStore implements the store interface.
var _ folder.Store = (*FolderUnifiedStoreImpl)(nil)
func ProvideUnifiedStore(k8sHandler *foldk8sHandler) *FolderUnifiedStoreImpl {
func ProvideUnifiedStore(k8sHandler *foldk8sHandler, userService user.Service) *FolderUnifiedStoreImpl {
return &FolderUnifiedStoreImpl{
k8sclient: k8sHandler,
log: log.New("folder-store"),
k8sclient: k8sHandler,
log: log.New("folder-store"),
userService: userService,
}
}
@ -60,7 +63,7 @@ func (ss *FolderUnifiedStoreImpl) Create(ctx context.Context, cmd folder.CreateF
return nil, err
}
folder, err := internalfolders.UnstructuredToLegacyFolder(out)
folder, err := ss.UnstructuredToLegacyFolder(ctx, out)
if err != nil {
return nil, err
}
@ -135,7 +138,7 @@ func (ss *FolderUnifiedStoreImpl) Update(ctx context.Context, cmd folder.UpdateF
return nil, err
}
return internalfolders.UnstructuredToLegacyFolder(out)
return ss.UnstructuredToLegacyFolder(ctx, out)
}
// If WithFullpath is true it computes also the full path of a folder.
@ -178,7 +181,7 @@ func (ss *FolderUnifiedStoreImpl) Get(ctx context.Context, q folder.GetFolderQue
return nil, dashboards.ErrFolderNotFound
}
return internalfolders.UnstructuredToLegacyFolder(out)
return ss.UnstructuredToLegacyFolder(ctx, out)
}
func (ss *FolderUnifiedStoreImpl) GetParents(ctx context.Context, q folder.GetParentsQuery) ([]*folder.Folder, error) {
@ -206,7 +209,7 @@ func (ss *FolderUnifiedStoreImpl) GetParents(ctx context.Context, q folder.GetPa
return nil, err
}
folder, err := internalfolders.UnstructuredToLegacyFolder(out)
folder, err := ss.UnstructuredToLegacyFolder(ctx, out)
if err != nil {
return nil, err
}
@ -245,9 +248,9 @@ func (ss *FolderUnifiedStoreImpl) GetChildren(ctx context.Context, q folder.GetC
hits := make([]*folder.Folder, 0)
for _, item := range out.Items {
// convert item to legacy folder format
f, err := internalfolders.UnstructuredToLegacyFolder(&item)
f, err := ss.UnstructuredToLegacyFolder(ctx, &item)
if f == nil {
return nil, fmt.Errorf("unable covert unstructured item to legacy folder %w", err)
return nil, fmt.Errorf("unable to convert unstructured item to legacy folder %w", err)
}
// it we are at root level, skip subfolder
@ -345,9 +348,9 @@ func (ss *FolderUnifiedStoreImpl) GetFolders(ctx context.Context, q folder.GetFo
m := map[string]*folder.Folder{}
for _, item := range out.Items {
// convert item to legacy folder format
f, err := internalfolders.UnstructuredToLegacyFolder(&item)
f, err := ss.UnstructuredToLegacyFolder(ctx, &item)
if f == nil {
return nil, fmt.Errorf("unable covert unstructured item to legacy folder %w", err)
return nil, fmt.Errorf("unable to convert unstructured item to legacy folder %w", err)
}
m[f.UID] = f
@ -405,9 +408,9 @@ func (ss *FolderUnifiedStoreImpl) GetDescendants(ctx context.Context, orgID int6
nodes := map[string]*folder.Folder{}
for _, item := range out.Items {
// convert item to legacy folder format
f, err := internalfolders.UnstructuredToLegacyFolder(&item)
f, err := ss.UnstructuredToLegacyFolder(ctx, &item)
if f == nil {
return nil, fmt.Errorf("unable covert unstructured item to legacy folder %w", err)
return nil, fmt.Errorf("unable to convert unstructured item to legacy folder %w", err)
}
nodes[f.UID] = f

Loading…
Cancel
Save