K8s Dashboards: Fix Tags (#98417)

This commit is contained in:
Stephanie Hingtgen 2025-01-02 10:38:23 -07:00 committed by GitHub
parent 0e55e45f88
commit 01b3e56706
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 128 additions and 12 deletions

View File

@ -316,6 +316,7 @@ type DashboardSearchProjection struct {
FolderSlug string
FolderTitle string
SortMeta int64
Tags []string
Deleted *time.Time
}

View File

@ -839,20 +839,21 @@ func (dr *DashboardServiceImpl) FindDashboards(ctx context.Context, query *dashb
query.OrgId = requester.GetOrgID()
}
results, err := dr.searchDashboardsThroughK8s(ctx, query)
response, err := dr.searchDashboardsThroughK8sRaw(ctx, query)
if err != nil {
return nil, err
}
finalResults := make([]dashboards.DashboardSearchProjection, len(results))
for i, result := range results {
finalResults := make([]dashboards.DashboardSearchProjection, len(response.Hits))
for i, hit := range response.Hits {
finalResults[i] = dashboards.DashboardSearchProjection{
UID: result.UID,
OrgID: result.OrgID,
Title: result.Title,
Slug: result.Slug,
UID: hit.Name,
OrgID: query.OrgId,
Title: hit.Title,
Slug: slugify.Slugify(hit.Title),
IsFolder: false,
FolderUID: result.FolderUID,
FolderUID: hit.Folder,
Tags: hit.Tags,
}
}
@ -928,6 +929,13 @@ func makeQueryResult(query *dashboards.FindPersistedDashboardsQuery, res []dashb
Tags: []string{},
}
// when searching through unified storage, the dashboard will come as one
// item, when searching through legacy, the dashboard will come multiple times
// per tag. So we need to add the array here for unified, and the term below for legacy.
if item.Tags != nil {
hit.Tags = item.Tags
}
// nolint:staticcheck
if item.FolderID > 0 {
hit.FolderURL = dashboards.GetFolderURL(item.FolderUID, item.FolderSlug)
@ -954,7 +962,41 @@ func makeQueryResult(query *dashboards.FindPersistedDashboardsQuery, res []dashb
}
func (dr *DashboardServiceImpl) GetDashboardTags(ctx context.Context, query *dashboards.GetDashboardTagsQuery) ([]*dashboards.DashboardTagCloudItem, error) {
// TODO: use k8s client to get dashboards first, and then filter tags and join
if dr.features.IsEnabled(ctx, featuremgmt.FlagKubernetesCliDashboards) {
res, err := dr.k8sclient.getSearcher().Search(ctx, &resource.ResourceSearchRequest{
Options: &resource.ListOptions{
Key: &resource.ResourceKey{
Namespace: dr.k8sclient.getNamespace(query.OrgID),
Group: "dashboard.grafana.app",
Resource: "dashboards",
},
},
Facet: map[string]*resource.ResourceSearchRequest_Facet{
"tags": {
Field: "tags",
Limit: 100000,
},
},
Limit: 100000})
if err != nil {
return nil, err
}
facet, ok := res.Facet["tags"]
if !ok {
return []*dashboards.DashboardTagCloudItem{}, nil
}
results := make([]*dashboards.DashboardTagCloudItem, len(facet.Terms))
for i, item := range facet.Terms {
results[i] = &dashboards.DashboardTagCloudItem{
Term: item.Term,
Count: int(item.Count),
}
}
return results, nil
}
return dr.dashboardStore.GetDashboardTags(ctx, query)
}
@ -1206,7 +1248,7 @@ func (dr *DashboardServiceImpl) listDashboardsThroughK8s(ctx context.Context, or
return dashboards, nil
}
func (dr *DashboardServiceImpl) searchDashboardsThroughK8s(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) ([]*dashboards.Dashboard, error) {
func (dr *DashboardServiceImpl) searchDashboardsThroughK8sRaw(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) (*v0alpha1.SearchResults, error) {
dashboardskey := &resource.ResourceKey{
Namespace: dr.k8sclient.getNamespace(query.OrgId),
Group: "dashboard.grafana.app",
@ -1287,7 +1329,14 @@ func (dr *DashboardServiceImpl) searchDashboardsThroughK8s(ctx context.Context,
return nil, err
}
response := ParseResults(res, 0)
return ParseResults(res, 0), nil
}
func (dr *DashboardServiceImpl) searchDashboardsThroughK8s(ctx context.Context, query *dashboards.FindPersistedDashboardsQuery) ([]*dashboards.Dashboard, error) {
response, err := dr.searchDashboardsThroughK8sRaw(ctx, query)
if err != nil {
return nil, err
}
result := make([]*dashboards.Dashboard, len(response.Hits))
for i, hit := range response.Hits {
result[i] = &dashboards.Dashboard{

View File

@ -660,7 +660,10 @@ func TestSearchDashboards(t *testing.T) {
Type: "dash-db",
URI: "db/dashboard-1",
URL: "/d/uid1/dashboard-1",
Tags: []string{},
Tags: []string{
"tag1",
"tag2",
},
},
{
UID: "uid2",
@ -683,6 +686,7 @@ func TestSearchDashboards(t *testing.T) {
Slug: "dashboard-1",
OrgID: 1,
Title: "Dashboard 1",
Tags: []string{"tag1", "tag2"},
},
{
UID: "uid2",
@ -709,6 +713,9 @@ func TestSearchDashboards(t *testing.T) {
{
Name: "folder",
},
{
Name: "tags",
},
},
Rows: []*resource.ResourceTableRow{
{
@ -719,6 +726,7 @@ func TestSearchDashboards(t *testing.T) {
Cells: [][]byte{
[]byte("Dashboard 1"),
[]byte(""),
[]byte("[\"tag1\", \"tag2\"]"),
},
},
{
@ -729,6 +737,7 @@ func TestSearchDashboards(t *testing.T) {
Cells: [][]byte{
[]byte("Dashboard 2"),
[]byte(""),
[]byte(""),
},
},
},
@ -958,6 +967,63 @@ func TestUnstructuredToLegacyDashboard(t *testing.T) {
})
}
func TestGetDashboardTags(t *testing.T) {
fakeStore := dashboards.FakeDashboardStore{}
defer fakeStore.AssertExpectations(t)
service := &DashboardServiceImpl{
cfg: setting.NewCfg(),
dashboardStore: &fakeStore,
}
expectedResult := []*dashboards.DashboardTagCloudItem{
{
Term: "tag1",
Count: 1,
},
{
Term: "tag2",
Count: 3,
},
}
query := &dashboards.GetDashboardTagsQuery{
OrgID: 1,
}
t.Run("Should fallback to dashboard store if Kubernetes feature flags are not enabled", func(t *testing.T) {
service.features = featuremgmt.WithFeatures()
fakeStore.On("GetDashboardTags", mock.Anything, query).Return(expectedResult, nil).Once()
result, err := service.GetDashboardTags(context.Background(), query)
require.NoError(t, err)
require.Equal(t, expectedResult, result)
fakeStore.AssertExpectations(t)
})
t.Run("Should use Kubernetes client if feature flags are enabled", func(t *testing.T) {
ctx, k8sClientMock, k8sResourceMock := setupK8sDashboardTests(service)
k8sClientMock.On("getClient", mock.Anything, int64(1)).Return(k8sResourceMock, true).Once()
k8sClientMock.searcher.On("Search", mock.Anything).Return(&resource.ResourceSearchResponse{
Facet: map[string]*resource.ResourceSearchResponse_Facet{
"tags": {
Terms: []*resource.ResourceSearchResponse_TermFacet{
{
Term: "tag1",
Count: 1,
},
{
Term: "tag2",
Count: 3,
},
},
},
},
}, nil)
result, err := service.GetDashboardTags(ctx, query)
require.NoError(t, err)
require.Equal(t, expectedResult, result)
fakeStore.AssertExpectations(t)
})
}
func TestLegacySaveCommandToUnstructured(t *testing.T) {
namespace := "test-namespace"
t.Run("successfully converts save command to unstructured", func(t *testing.T) {