mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
FindDashboards: filter by dashboard type (#100160)
This commit is contained in:
parent
f7d476e408
commit
495aa65c6e
@ -46,6 +46,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards"
|
||||
"github.com/grafana/grafana/pkg/services/quota"
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
||||
"github.com/grafana/grafana/pkg/services/store/entity"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@ -232,7 +233,7 @@ func (dr *DashboardServiceImpl) GetProvisionedDashboardData(ctx context.Context,
|
||||
for _, org := range orgs {
|
||||
func(orgID int64) {
|
||||
g.Go(func() error {
|
||||
res, err := dr.searchProvisionedDashboardsThroughK8s(ctx, dashboards.FindPersistedDashboardsQuery{
|
||||
res, err := dr.searchProvisionedDashboardsThroughK8s(ctx, &dashboards.FindPersistedDashboardsQuery{
|
||||
ProvisionedRepo: name,
|
||||
OrgId: orgID,
|
||||
})
|
||||
@ -273,7 +274,7 @@ func (dr *DashboardServiceImpl) GetProvisionedDashboardDataByDashboardID(ctx con
|
||||
}
|
||||
|
||||
for _, org := range orgs {
|
||||
res, err := dr.searchProvisionedDashboardsThroughK8s(ctx, dashboards.FindPersistedDashboardsQuery{
|
||||
res, err := dr.searchProvisionedDashboardsThroughK8s(ctx, &dashboards.FindPersistedDashboardsQuery{
|
||||
OrgId: org.ID,
|
||||
DashboardIds: []int64{dashboardID},
|
||||
})
|
||||
@ -300,7 +301,7 @@ func (dr *DashboardServiceImpl) GetProvisionedDashboardDataByDashboardUID(ctx co
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
res, err := dr.searchProvisionedDashboardsThroughK8s(ctx, dashboards.FindPersistedDashboardsQuery{
|
||||
res, err := dr.searchProvisionedDashboardsThroughK8s(ctx, &dashboards.FindPersistedDashboardsQuery{
|
||||
OrgId: orgID,
|
||||
DashboardUIDs: []string{dashboardUID},
|
||||
})
|
||||
@ -559,7 +560,7 @@ func (dr *DashboardServiceImpl) DeleteOrphanedProvisionedDashboards(ctx context.
|
||||
for _, org := range orgs {
|
||||
ctx, _ := identity.WithServiceIdentity(ctx, org.ID)
|
||||
// find all dashboards in the org that have a file repo set that is not in the given readers list
|
||||
foundDashs, err := dr.searchProvisionedDashboardsThroughK8s(ctx, dashboards.FindPersistedDashboardsQuery{
|
||||
foundDashs, err := dr.searchProvisionedDashboardsThroughK8s(ctx, &dashboards.FindPersistedDashboardsQuery{
|
||||
ProvisionedReposNotIn: cmd.ReaderNames,
|
||||
OrgId: org.ID,
|
||||
})
|
||||
@ -1436,7 +1437,12 @@ func (dr *DashboardServiceImpl) DeleteInFolders(ctx context.Context, orgID int64
|
||||
}
|
||||
|
||||
// We need a list of dashboard uids inside the folder to delete related public dashboards
|
||||
dashes, err := dr.dashboardStore.FindDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{SignedInUser: u, FolderUIDs: folderUIDs, OrgId: orgID})
|
||||
dashes, err := dr.dashboardStore.FindDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{
|
||||
SignedInUser: u,
|
||||
FolderUIDs: folderUIDs,
|
||||
OrgId: orgID,
|
||||
Type: searchstore.TypeDashboard,
|
||||
})
|
||||
if err != nil {
|
||||
return folder.ErrInternal.Errorf("failed to fetch dashboards: %w", err)
|
||||
}
|
||||
@ -1729,7 +1735,11 @@ type dashboardProvisioningWithUID struct {
|
||||
DashboardUID string
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) searchProvisionedDashboardsThroughK8s(ctx context.Context, query dashboards.FindPersistedDashboardsQuery) ([]*dashboardProvisioningWithUID, error) {
|
||||
func (dr *DashboardServiceImpl) searchProvisionedDashboardsThroughK8s(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) ([]*dashboardProvisioningWithUID, error) {
|
||||
if query == nil {
|
||||
return nil, errors.New("query cannot be nil")
|
||||
}
|
||||
|
||||
ctx, _ = identity.WithServiceIdentity(ctx, query.OrgId)
|
||||
|
||||
if query.ProvisionedRepo != "" {
|
||||
@ -1744,7 +1754,9 @@ func (dr *DashboardServiceImpl) searchProvisionedDashboardsThroughK8s(ctx contex
|
||||
query.ProvisionedReposNotIn = repos
|
||||
}
|
||||
|
||||
searchResults, err := dr.searchDashboardsThroughK8sRaw(ctx, &query)
|
||||
query.Type = searchstore.TypeDashboard
|
||||
|
||||
searchResults, err := dr.searchDashboardsThroughK8sRaw(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1807,6 +1819,11 @@ func (dr *DashboardServiceImpl) searchProvisionedDashboardsThroughK8s(ctx contex
|
||||
}
|
||||
|
||||
func (dr *DashboardServiceImpl) searchDashboardsThroughK8s(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) ([]*dashboards.Dashboard, error) {
|
||||
if query == nil {
|
||||
return nil, errors.New("query cannot be nil")
|
||||
}
|
||||
query.Type = searchstore.TypeDashboard
|
||||
|
||||
response, err := dr.searchDashboardsThroughK8sRaw(ctx, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -1899,6 +1899,134 @@ func TestCountInFolders(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestSearchDashboardsThroughK8sRaw(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
k8sCliMock := new(client.MockK8sHandler)
|
||||
service := &DashboardServiceImpl{k8sclient: k8sCliMock}
|
||||
query := &dashboards.FindPersistedDashboardsQuery{
|
||||
OrgId: 1,
|
||||
}
|
||||
k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{
|
||||
Results: &resource.ResourceTable{
|
||||
Columns: []*resource.ResourceTableColumnDefinition{
|
||||
{
|
||||
Name: "title",
|
||||
Type: resource.ResourceTableColumnDefinition_STRING,
|
||||
},
|
||||
{
|
||||
Name: "folder",
|
||||
Type: resource.ResourceTableColumnDefinition_STRING,
|
||||
},
|
||||
},
|
||||
Rows: []*resource.ResourceTableRow{
|
||||
{
|
||||
Key: &resource.ResourceKey{
|
||||
Name: "uid",
|
||||
Resource: "dashboard",
|
||||
},
|
||||
Cells: [][]byte{
|
||||
[]byte("Dashboard 1"),
|
||||
[]byte("folder1"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TotalHits: 1,
|
||||
}, nil)
|
||||
res, err := service.searchDashboardsThroughK8s(ctx, query)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []*dashboards.Dashboard{
|
||||
{
|
||||
UID: "uid",
|
||||
OrgID: 1,
|
||||
FolderUID: "folder1",
|
||||
Title: "Dashboard 1",
|
||||
Slug: "dashboard-1", // should be slugified
|
||||
},
|
||||
}, res)
|
||||
assert.Equal(t, "dash-db", query.Type) // query type should be added
|
||||
}
|
||||
|
||||
func TestSearchProvisionedDashboardsThroughK8sRaw(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
k8sCliMock := new(client.MockK8sHandler)
|
||||
service := &DashboardServiceImpl{k8sclient: k8sCliMock}
|
||||
query := &dashboards.FindPersistedDashboardsQuery{
|
||||
OrgId: 1,
|
||||
}
|
||||
dashboardUnstructuredProvisioned := unstructured.Unstructured{Object: map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"name": "uid",
|
||||
"annotations": map[string]any{
|
||||
utils.AnnoKeyRepoName: fileProvisionedRepoPrefix + "test",
|
||||
utils.AnnoKeyRepoHash: "hash",
|
||||
utils.AnnoKeyRepoPath: "path/to/file",
|
||||
utils.AnnoKeyRepoTimestamp: "2025-01-01T00:00:00Z",
|
||||
},
|
||||
},
|
||||
"spec": map[string]any{},
|
||||
}}
|
||||
dashboardUnstructuredNotProvisioned := unstructured.Unstructured{Object: map[string]any{
|
||||
"metadata": map[string]any{
|
||||
"name": "uid2",
|
||||
},
|
||||
"spec": map[string]any{},
|
||||
}}
|
||||
k8sCliMock.On("Search", mock.Anything, mock.Anything, mock.Anything).Return(&resource.ResourceSearchResponse{
|
||||
Results: &resource.ResourceTable{
|
||||
Columns: []*resource.ResourceTableColumnDefinition{
|
||||
{
|
||||
Name: "title",
|
||||
Type: resource.ResourceTableColumnDefinition_STRING,
|
||||
},
|
||||
{
|
||||
Name: "folder",
|
||||
Type: resource.ResourceTableColumnDefinition_STRING,
|
||||
},
|
||||
},
|
||||
Rows: []*resource.ResourceTableRow{
|
||||
{
|
||||
Key: &resource.ResourceKey{
|
||||
Name: "uid",
|
||||
Resource: "dashboard",
|
||||
},
|
||||
Cells: [][]byte{
|
||||
[]byte("Dashboard 1"),
|
||||
[]byte("folder1"),
|
||||
},
|
||||
},
|
||||
{
|
||||
Key: &resource.ResourceKey{
|
||||
Name: "uid2",
|
||||
Resource: "dashboard",
|
||||
},
|
||||
Cells: [][]byte{
|
||||
[]byte("Dashboard 2"),
|
||||
[]byte("folder2"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TotalHits: 1,
|
||||
}, nil)
|
||||
k8sCliMock.On("Get", mock.Anything, "uid", mock.Anything, mock.Anything, mock.Anything).Return(&dashboardUnstructuredProvisioned, nil).Once()
|
||||
k8sCliMock.On("Get", mock.Anything, "uid2", mock.Anything, mock.Anything, mock.Anything).Return(&dashboardUnstructuredNotProvisioned, nil).Once()
|
||||
res, err := service.searchProvisionedDashboardsThroughK8s(ctx, query)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, []*dashboardProvisioningWithUID{
|
||||
{
|
||||
DashboardUID: "uid",
|
||||
DashboardProvisioning: dashboards.DashboardProvisioning{
|
||||
Name: "test",
|
||||
ExternalID: "path/to/file",
|
||||
CheckSum: "hash",
|
||||
Updated: 1735689600,
|
||||
},
|
||||
},
|
||||
}, res) // only should return the one provisioned dashboard
|
||||
assert.Equal(t, "dash-db", query.Type) // query type should be added as dashboards only
|
||||
}
|
||||
|
||||
func TestLegacySaveCommandToUnstructured(t *testing.T) {
|
||||
namespace := "test-namespace"
|
||||
t.Run("successfully converts save command to unstructured", func(t *testing.T) {
|
||||
|
@ -37,6 +37,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
||||
"github.com/grafana/grafana/pkg/services/store/entity"
|
||||
"github.com/grafana/grafana/pkg/services/supportbundles"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
@ -1028,7 +1029,12 @@ func (s *Service) legacyDelete(ctx context.Context, cmd *folder.DeleteFolderComm
|
||||
// if dashboard restore is on we don't delete public dashboards, the hard delete will take care of it later
|
||||
if !s.features.IsEnabledGlobally(featuremgmt.FlagDashboardRestore) {
|
||||
// We need a list of dashboard uids inside the folder to delete related public dashboards
|
||||
dashes, err := s.dashboardStore.FindDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{SignedInUser: cmd.SignedInUser, FolderUIDs: folderUIDs, OrgId: cmd.OrgID})
|
||||
dashes, err := s.dashboardStore.FindDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{
|
||||
SignedInUser: cmd.SignedInUser,
|
||||
FolderUIDs: folderUIDs,
|
||||
OrgId: cmd.OrgID,
|
||||
Type: searchstore.TypeDashboard,
|
||||
})
|
||||
if err != nil {
|
||||
return folder.ErrInternal.Errorf("failed to fetch dashboards: %w", err)
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/folder"
|
||||
"github.com/grafana/grafana/pkg/services/guardian"
|
||||
"github.com/grafana/grafana/pkg/services/search/model"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
||||
"github.com/grafana/grafana/pkg/services/store/entity"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/resource"
|
||||
@ -737,7 +738,12 @@ func (s *Service) deleteFromApiServer(ctx context.Context, cmd *folder.DeleteFol
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dashes, err := s.dashboardStore.FindDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{SignedInUser: cmd.SignedInUser, FolderUIDs: folders, OrgId: cmd.OrgID})
|
||||
dashes, err := s.dashboardStore.FindDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{
|
||||
SignedInUser: cmd.SignedInUser,
|
||||
FolderUIDs: folders,
|
||||
OrgId: cmd.OrgID,
|
||||
Type: searchstore.TypeDashboard,
|
||||
})
|
||||
if err != nil {
|
||||
return folder.ErrInternal.Errorf("failed to fetch dashboards: %w", err)
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/org"
|
||||
"github.com/grafana/grafana/pkg/services/search"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrator"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
)
|
||||
@ -252,6 +253,7 @@ func (l *LibraryElementService) deleteLibraryElement(c context.Context, signedIn
|
||||
// then find the dashboards that were supposed to be connected to this element
|
||||
_, requester := identity.WithServiceIdentity(c, signedInUser.GetOrgID())
|
||||
dashs, err := l.dashboardsService.FindDashboards(c, &dashboards.FindPersistedDashboardsQuery{
|
||||
Type: searchstore.TypeDashboard,
|
||||
OrgId: signedInUser.GetOrgID(),
|
||||
DashboardIds: dashboardIDs,
|
||||
SignedInUser: requester, // a user may be able to delete a library element but not read all dashboards. We still need to run this check, so we don't allow deleting elements if dashboards are connected
|
||||
|
@ -25,6 +25,7 @@ import (
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/service/intervalv2"
|
||||
"github.com/grafana/grafana/pkg/services/publicdashboards/validation"
|
||||
"github.com/grafana/grafana/pkg/services/query"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore/searchstore"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/util"
|
||||
@ -375,7 +376,13 @@ func (pd *PublicDashboardServiceImpl) FindAllWithPagination(ctx context.Context,
|
||||
dashUIDs[i] = pubdash.DashboardUid
|
||||
}
|
||||
|
||||
dashboardsFound, err := pd.dashboardService.FindDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{OrgId: query.OrgID, DashboardUIDs: dashUIDs, SignedInUser: query.User, Limit: int64(len(dashUIDs))})
|
||||
dashboardsFound, err := pd.dashboardService.FindDashboards(ctx, &dashboards.FindPersistedDashboardsQuery{
|
||||
OrgId: query.OrgID,
|
||||
DashboardUIDs: dashUIDs,
|
||||
SignedInUser: query.User,
|
||||
Limit: int64(len(dashUIDs)),
|
||||
Type: searchstore.TypeDashboard,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, ErrInternalServerError.Errorf("FindAllWithPagination: GetDashboards: %w", err)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user