mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
K8s Dashboards: Fix Tags (#98417)
This commit is contained in:
committed by
GitHub
parent
0e55e45f88
commit
01b3e56706
@@ -316,6 +316,7 @@ type DashboardSearchProjection struct {
|
|||||||
FolderSlug string
|
FolderSlug string
|
||||||
FolderTitle string
|
FolderTitle string
|
||||||
SortMeta int64
|
SortMeta int64
|
||||||
|
Tags []string
|
||||||
Deleted *time.Time
|
Deleted *time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -839,20 +839,21 @@ func (dr *DashboardServiceImpl) FindDashboards(ctx context.Context, query *dashb
|
|||||||
query.OrgId = requester.GetOrgID()
|
query.OrgId = requester.GetOrgID()
|
||||||
}
|
}
|
||||||
|
|
||||||
results, err := dr.searchDashboardsThroughK8s(ctx, query)
|
response, err := dr.searchDashboardsThroughK8sRaw(ctx, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
finalResults := make([]dashboards.DashboardSearchProjection, len(results))
|
finalResults := make([]dashboards.DashboardSearchProjection, len(response.Hits))
|
||||||
for i, result := range results {
|
for i, hit := range response.Hits {
|
||||||
finalResults[i] = dashboards.DashboardSearchProjection{
|
finalResults[i] = dashboards.DashboardSearchProjection{
|
||||||
UID: result.UID,
|
UID: hit.Name,
|
||||||
OrgID: result.OrgID,
|
OrgID: query.OrgId,
|
||||||
Title: result.Title,
|
Title: hit.Title,
|
||||||
Slug: result.Slug,
|
Slug: slugify.Slugify(hit.Title),
|
||||||
IsFolder: false,
|
IsFolder: false,
|
||||||
FolderUID: result.FolderUID,
|
FolderUID: hit.Folder,
|
||||||
|
Tags: hit.Tags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -928,6 +929,13 @@ func makeQueryResult(query *dashboards.FindPersistedDashboardsQuery, res []dashb
|
|||||||
Tags: []string{},
|
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
|
// nolint:staticcheck
|
||||||
if item.FolderID > 0 {
|
if item.FolderID > 0 {
|
||||||
hit.FolderURL = dashboards.GetFolderURL(item.FolderUID, item.FolderSlug)
|
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) {
|
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)
|
return dr.dashboardStore.GetDashboardTags(ctx, query)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1206,7 +1248,7 @@ func (dr *DashboardServiceImpl) listDashboardsThroughK8s(ctx context.Context, or
|
|||||||
return dashboards, nil
|
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{
|
dashboardskey := &resource.ResourceKey{
|
||||||
Namespace: dr.k8sclient.getNamespace(query.OrgId),
|
Namespace: dr.k8sclient.getNamespace(query.OrgId),
|
||||||
Group: "dashboard.grafana.app",
|
Group: "dashboard.grafana.app",
|
||||||
@@ -1287,7 +1329,14 @@ func (dr *DashboardServiceImpl) searchDashboardsThroughK8s(ctx context.Context,
|
|||||||
return nil, err
|
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))
|
result := make([]*dashboards.Dashboard, len(response.Hits))
|
||||||
for i, hit := range response.Hits {
|
for i, hit := range response.Hits {
|
||||||
result[i] = &dashboards.Dashboard{
|
result[i] = &dashboards.Dashboard{
|
||||||
|
|||||||
@@ -660,7 +660,10 @@ func TestSearchDashboards(t *testing.T) {
|
|||||||
Type: "dash-db",
|
Type: "dash-db",
|
||||||
URI: "db/dashboard-1",
|
URI: "db/dashboard-1",
|
||||||
URL: "/d/uid1/dashboard-1",
|
URL: "/d/uid1/dashboard-1",
|
||||||
Tags: []string{},
|
Tags: []string{
|
||||||
|
"tag1",
|
||||||
|
"tag2",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
UID: "uid2",
|
UID: "uid2",
|
||||||
@@ -683,6 +686,7 @@ func TestSearchDashboards(t *testing.T) {
|
|||||||
Slug: "dashboard-1",
|
Slug: "dashboard-1",
|
||||||
OrgID: 1,
|
OrgID: 1,
|
||||||
Title: "Dashboard 1",
|
Title: "Dashboard 1",
|
||||||
|
Tags: []string{"tag1", "tag2"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
UID: "uid2",
|
UID: "uid2",
|
||||||
@@ -709,6 +713,9 @@ func TestSearchDashboards(t *testing.T) {
|
|||||||
{
|
{
|
||||||
Name: "folder",
|
Name: "folder",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "tags",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
Rows: []*resource.ResourceTableRow{
|
Rows: []*resource.ResourceTableRow{
|
||||||
{
|
{
|
||||||
@@ -719,6 +726,7 @@ func TestSearchDashboards(t *testing.T) {
|
|||||||
Cells: [][]byte{
|
Cells: [][]byte{
|
||||||
[]byte("Dashboard 1"),
|
[]byte("Dashboard 1"),
|
||||||
[]byte(""),
|
[]byte(""),
|
||||||
|
[]byte("[\"tag1\", \"tag2\"]"),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -729,6 +737,7 @@ func TestSearchDashboards(t *testing.T) {
|
|||||||
Cells: [][]byte{
|
Cells: [][]byte{
|
||||||
[]byte("Dashboard 2"),
|
[]byte("Dashboard 2"),
|
||||||
[]byte(""),
|
[]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) {
|
func TestLegacySaveCommandToUnstructured(t *testing.T) {
|
||||||
namespace := "test-namespace"
|
namespace := "test-namespace"
|
||||||
t.Run("successfully converts save command to unstructured", func(t *testing.T) {
|
t.Run("successfully converts save command to unstructured", func(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user