K8s: Dashboards: Reduce db calls to get users on list (#103020)

This commit is contained in:
Stephanie Hingtgen
2025-03-27 22:57:49 +02:00
committed by GitHub
parent e6480a050c
commit 12c5b81850
14 changed files with 207 additions and 89 deletions
@@ -276,13 +276,9 @@ func (s *Service) listHistoryThroughK8s(ctx context.Context, orgID int64, dashbo
return nil, dashboards.ErrDashboardNotFound
}
dashboards := make([]*dashver.DashboardVersionDTO, len(out.Items))
for i, item := range out.Items {
dash, err := s.UnstructuredToLegacyDashboardVersion(ctx, &item, orgID)
if err != nil {
return nil, err
}
dashboards[i] = dash
dashboards, err := s.UnstructuredToLegacyDashboardVersionList(ctx, out.Items, orgID)
if err != nil {
return nil, err
}
return &dashver.DashboardVersionResponse{
@@ -292,6 +288,51 @@ func (s *Service) listHistoryThroughK8s(ctx context.Context, orgID int64, dashbo
}
func (s *Service) UnstructuredToLegacyDashboardVersion(ctx context.Context, item *unstructured.Unstructured, orgID int64) (*dashver.DashboardVersionDTO, error) {
obj, err := utils.MetaAccessor(item)
if err != nil {
return nil, err
}
users, err := s.k8sclient.GetUsersFromMeta(ctx, []string{obj.GetCreatedBy(), obj.GetUpdatedBy()})
if err != nil {
return nil, err
}
return s.unstructuredToLegacyDashboardVersionWithUsers(item, users)
}
func (s *Service) UnstructuredToLegacyDashboardVersionList(ctx context.Context, items []unstructured.Unstructured, orgID int64) ([]*dashver.DashboardVersionDTO, error) {
// get users ahead of time to do just one db call, rather than 2 per item in the list
userMeta := []string{}
for _, item := range items {
obj, err := utils.MetaAccessor(&item)
if err != nil {
return nil, err
}
if obj.GetCreatedBy() != "" {
userMeta = append(userMeta, obj.GetCreatedBy())
}
if obj.GetUpdatedBy() != "" {
userMeta = append(userMeta, obj.GetUpdatedBy())
}
}
users, err := s.k8sclient.GetUsersFromMeta(ctx, userMeta)
if err != nil {
return nil, err
}
versions := make([]*dashver.DashboardVersionDTO, len(items))
for i, item := range items {
version, err := s.unstructuredToLegacyDashboardVersionWithUsers(&item, users)
if err != nil {
return nil, err
}
versions[i] = version
}
return versions, nil
}
func (s *Service) unstructuredToLegacyDashboardVersionWithUsers(item *unstructured.Unstructured, users map[string]*user.User) (*dashver.DashboardVersionDTO, error) {
spec, ok := item.Object["spec"].(map[string]any)
if !ok {
return nil, errors.New("error parsing dashboard from k8s response")
@@ -312,19 +353,21 @@ func (s *Service) UnstructuredToLegacyDashboardVersion(ctx context.Context, item
spec["version"] = dashVersion
}
createdBy, err := s.k8sclient.GetUserFromMeta(ctx, obj.GetCreatedBy())
if err != nil {
return nil, err
var createdBy *user.User
if creator, ok := users[obj.GetCreatedBy()]; ok {
createdBy = creator
}
// if updated by is set, then this version of the dashboard was "created"
// by that user
if obj.GetUpdatedBy() != "" {
updatedBy, err := s.k8sclient.GetUserFromMeta(ctx, obj.GetUpdatedBy())
if err == nil && updatedBy != nil {
createdBy = updatedBy
}
if updater, ok := users[obj.GetUpdatedBy()]; ok {
createdBy = updater
}
createdByID := int64(0)
if createdBy != nil {
createdByID = createdBy.ID
}
created := obj.GetCreationTimestamp().Time
if updated, err := obj.GetUpdatedTimestamp(); err == nil && updated != nil {
created = *updated
@@ -335,20 +378,18 @@ func (s *Service) UnstructuredToLegacyDashboardVersion(ctx context.Context, item
return nil, err
}
out := dashver.DashboardVersionDTO{
return &dashver.DashboardVersionDTO{
ID: dashVersion,
DashboardID: obj.GetDeprecatedInternalID(), // nolint:staticcheck
DashboardUID: uid,
Created: created,
CreatedBy: createdBy.ID,
CreatedBy: createdByID,
Message: obj.GetMessage(),
RestoredFrom: restoreVer,
Version: int(dashVersion),
ParentVersion: int(parentVersion),
Data: simplejson.NewFromAny(spec),
}
return &out, nil
}, nil
}
var restoreMsg = "Restored from version "
@@ -73,7 +73,7 @@ func TestDashboardVersionService(t *testing.T) {
obj, err := utils.MetaAccessor(dash)
require.NoError(t, err)
obj.SetUpdatedTimestamp(&updatedTimestamp)
mockCli.On("GetUserFromMeta", mock.Anything, "user:1").Return(&user.User{ID: 1}, nil)
mockCli.On("GetUsersFromMeta", mock.Anything, []string{"user:1", ""}).Return(map[string]*user.User{"user:1": &user.User{ID: 1}}, nil)
mockCli.On("List", mock.Anything, int64(1), mock.Anything).Return(&unstructured.UnstructuredList{
Items: []unstructured.Unstructured{*dash}}, nil).Once()
res, err := dashboardVersionService.Get(context.Background(), &dashver.GetDashboardVersionQuery{
@@ -93,7 +93,7 @@ func TestDashboardVersionService(t *testing.T) {
Data: simplejson.NewFromAny(map[string]any{"uid": "uid", "version": int64(10), "hello": "world"}),
})
mockCli.On("GetUserFromMeta", mock.Anything, "user:2").Return(&user.User{ID: 2}, nil)
mockCli.On("GetUsersFromMeta", mock.Anything, []string{"user:1", "user:2"}).Return(map[string]*user.User{"user:1": {ID: 1}, "user:2": {ID: 2}}, nil)
mockCli.On("List", mock.Anything, int64(1), mock.Anything).Return(&unstructured.UnstructuredList{
Items: []unstructured.Unstructured{{
Object: map[string]any{
@@ -269,7 +269,7 @@ func TestListDashboardVersions(t *testing.T) {
Return(&dashboards.DashboardRef{UID: "uid"}, nil)
query := dashver.ListDashboardVersionsQuery{DashboardID: 42}
mockCli.On("GetUserFromMeta", mock.Anything, mock.Anything).Return(&user.User{}, nil)
mockCli.On("GetUsersFromMeta", mock.Anything, mock.Anything).Return(map[string]*user.User{}, nil)
mockCli.On("List", mock.Anything, mock.Anything, mock.Anything).Return(&unstructured.UnstructuredList{
Items: []unstructured.Unstructured{{Object: map[string]any{
"metadata": map[string]any{