mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
PublicDashboards: Fix hidden queries execution (#57004)
PublicDashboards: Fix hidden queries execution
This commit is contained in:
@@ -46,17 +46,19 @@ func GroupQueriesByPanelId(dashboard *simplejson.Json) map[int64][]*simplejson.J
|
||||
for _, queryObj := range panel.Get("targets").MustArray() {
|
||||
query := simplejson.NewFromAny(queryObj)
|
||||
|
||||
// We dont support exemplars for public dashboards currently
|
||||
query.Del("exemplar")
|
||||
if hideAttr, exists := query.CheckGet("hide"); !exists || !hideAttr.MustBool() {
|
||||
// We dont support exemplars for public dashboards currently
|
||||
query.Del("exemplar")
|
||||
|
||||
// if query target has no datasource, set it to have the datasource on the panel
|
||||
if _, ok := query.CheckGet("datasource"); !ok {
|
||||
uid := GetDataSourceUidFromJson(panel)
|
||||
datasource := map[string]interface{}{"type": "public-ds", "uid": uid}
|
||||
query.Set("datasource", datasource)
|
||||
// if query target has no datasource, set it to have the datasource on the panel
|
||||
if _, ok := query.CheckGet("datasource"); !ok {
|
||||
uid := GetDataSourceUidFromJson(panel)
|
||||
datasource := map[string]interface{}{"type": "public-ds", "uid": uid}
|
||||
query.Set("datasource", datasource)
|
||||
}
|
||||
|
||||
panelQueries = append(panelQueries, query)
|
||||
}
|
||||
|
||||
panelQueries = append(panelQueries, query)
|
||||
}
|
||||
|
||||
result[panel.Get("id").MustInt64()] = panelQueries
|
||||
|
||||
@@ -303,6 +303,80 @@ const (
|
||||
],
|
||||
"schemaVersion": 21
|
||||
}`
|
||||
|
||||
dashboardWithOneHiddenQuery = `
|
||||
{
|
||||
"panels": [
|
||||
{
|
||||
"id": 2,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "_yxMP8Ynk"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "go_goroutines{job=\"$job\"}",
|
||||
"interval": "",
|
||||
"legendFormat": "",
|
||||
"refId": "A",
|
||||
"hide": true
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "promds2"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "query2",
|
||||
"interval": "",
|
||||
"legendFormat": "",
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "Panel Title",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 35
|
||||
}`
|
||||
dashboardWithAllHiddenQueries = `
|
||||
{
|
||||
"panels": [
|
||||
{
|
||||
"id": 2,
|
||||
"targets": [
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "_yxMP8Ynk"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "go_goroutines{job=\"$job\"}",
|
||||
"interval": "",
|
||||
"legendFormat": "",
|
||||
"refId": "A",
|
||||
"hide": true
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "promds2"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "query2",
|
||||
"interval": "",
|
||||
"legendFormat": "",
|
||||
"refId": "B",
|
||||
"hide": true
|
||||
}
|
||||
],
|
||||
"title": "Panel Title",
|
||||
"type": "timeseries"
|
||||
}
|
||||
],
|
||||
"schemaVersion": 35
|
||||
}`
|
||||
)
|
||||
|
||||
func TestGetUniqueDashboardDatasourceUids(t *testing.T) {
|
||||
@@ -458,6 +532,27 @@ func TestGroupQueriesByPanelId(t *testing.T) {
|
||||
"refId": "A"
|
||||
}`, string(query))
|
||||
})
|
||||
|
||||
t.Run("hidden query filtered", func(t *testing.T) {
|
||||
json, err := simplejson.NewJson([]byte(dashboardWithOneHiddenQuery))
|
||||
require.NoError(t, err)
|
||||
queries := GroupQueriesByPanelId(json)[2]
|
||||
|
||||
require.Len(t, queries, 1)
|
||||
for _, query := range queries {
|
||||
if hideAttr, exists := query.CheckGet("hide"); exists && hideAttr.MustBool() {
|
||||
require.Fail(t, "hidden queries should have been filtered")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("hidden query filtered, so empty queries returned", func(t *testing.T) {
|
||||
json, err := simplejson.NewJson([]byte(dashboardWithAllHiddenQueries))
|
||||
require.NoError(t, err)
|
||||
queries := GroupQueriesByPanelId(json)[2]
|
||||
|
||||
require.Len(t, queries, 0)
|
||||
})
|
||||
}
|
||||
|
||||
func TestGroupQueriesByDataSource(t *testing.T) {
|
||||
|
||||
@@ -213,6 +213,10 @@ func (pd *PublicDashboardServiceImpl) GetQueryDataResponse(ctx context.Context,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(metricReq.Queries) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
anonymousUser := pd.BuildAnonymousUser(ctx, dashboard)
|
||||
res, err := pd.QueryDataService.QueryData(ctx, anonymousUser, skipCache, metricReq)
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ func TestSavePublicDashboard(t *testing.T) {
|
||||
sqlStore := sqlstore.InitTestDB(t)
|
||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{})
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
|
||||
service := &PublicDashboardServiceImpl{
|
||||
log: log.New("test.logger"),
|
||||
@@ -164,7 +164,7 @@ func TestSavePublicDashboard(t *testing.T) {
|
||||
sqlStore := sqlstore.InitTestDB(t)
|
||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{})
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
|
||||
service := &PublicDashboardServiceImpl{
|
||||
log: log.New("test.logger"),
|
||||
@@ -195,7 +195,7 @@ func TestSavePublicDashboard(t *testing.T) {
|
||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
templateVars := make([]map[string]interface{}, 1)
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, templateVars)
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, templateVars, nil)
|
||||
|
||||
service := &PublicDashboardServiceImpl{
|
||||
log: log.New("test.logger"),
|
||||
@@ -255,7 +255,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||
sqlStore := sqlstore.InitTestDB(t)
|
||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{})
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
|
||||
service := &PublicDashboardServiceImpl{
|
||||
log: log.New("test.logger"),
|
||||
@@ -316,7 +316,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||
sqlStore := sqlstore.InitTestDB(t)
|
||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{})
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
|
||||
service := &PublicDashboardServiceImpl{
|
||||
log: log.New("test.logger"),
|
||||
@@ -365,7 +365,7 @@ func TestUpdatePublicDashboard(t *testing.T) {
|
||||
func TestBuildAnonymousUser(t *testing.T) {
|
||||
sqlStore := sqlstore.InitTestDB(t)
|
||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{})
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
service := &PublicDashboardServiceImpl{
|
||||
log: log.New("test.logger"),
|
||||
@@ -386,7 +386,7 @@ func TestGetMetricRequest(t *testing.T) {
|
||||
sqlStore := sqlstore.InitTestDB(t)
|
||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{})
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
publicDashboard := &PublicDashboard{
|
||||
Uid: "1",
|
||||
DashboardUid: dashboard.Uid,
|
||||
@@ -425,13 +425,67 @@ func TestGetMetricRequest(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetQueryDataResponse(t *testing.T) {
|
||||
sqlStore := sqlstore.InitTestDB(t)
|
||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
|
||||
service := &PublicDashboardServiceImpl{
|
||||
log: log.New("test.logger"),
|
||||
store: publicdashboardStore,
|
||||
intervalCalculator: intervalv2.NewCalculator(),
|
||||
}
|
||||
|
||||
publicDashboardQueryDTO := PublicDashboardQueryDTO{
|
||||
IntervalMs: int64(1),
|
||||
MaxDataPoints: int64(1),
|
||||
}
|
||||
|
||||
t.Run("Returns nil when query is hidden", func(t *testing.T) {
|
||||
hiddenQuery := map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "mysql",
|
||||
"uid": "ds1",
|
||||
},
|
||||
"hide": true,
|
||||
"refId": "A",
|
||||
}
|
||||
customPanels := []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"datasource": map[string]interface{}{
|
||||
"uid": "ds1",
|
||||
},
|
||||
"targets": []interface{}{hiddenQuery},
|
||||
}}
|
||||
|
||||
dashboard := insertTestDashboard(t, dashboardStore, "testDashWithHiddenQuery", 1, 0, true, []map[string]interface{}{}, customPanels)
|
||||
dto := &SavePublicDashboardConfigDTO{
|
||||
DashboardUid: dashboard.Uid,
|
||||
OrgId: dashboard.OrgId,
|
||||
UserId: 7,
|
||||
PublicDashboard: &PublicDashboard{
|
||||
IsEnabled: true,
|
||||
DashboardUid: "NOTTHESAME",
|
||||
OrgId: 9999999,
|
||||
TimeSettings: timeSettings,
|
||||
},
|
||||
}
|
||||
pubdashDto, err := service.SavePublicDashboardConfig(context.Background(), SignedInUser, dto)
|
||||
require.NoError(t, err)
|
||||
|
||||
resp, _ := service.GetQueryDataResponse(context.Background(), true, publicDashboardQueryDTO, 1, pubdashDto.AccessToken)
|
||||
require.Nil(t, resp)
|
||||
})
|
||||
}
|
||||
|
||||
func TestBuildMetricRequest(t *testing.T) {
|
||||
sqlStore := sqlstore.InitTestDB(t)
|
||||
dashboardStore := dashboardsDB.ProvideDashboardStore(sqlStore, sqlStore.Cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(sqlStore, sqlStore.Cfg))
|
||||
publicdashboardStore := database.ProvideStore(sqlStore)
|
||||
|
||||
publicDashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{})
|
||||
nonPublicDashboard := insertTestDashboard(t, dashboardStore, "testNonPublicDashie", 1, 0, true, []map[string]interface{}{})
|
||||
publicDashboard := insertTestDashboard(t, dashboardStore, "testDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
nonPublicDashboard := insertTestDashboard(t, dashboardStore, "testNonPublicDashie", 1, 0, true, []map[string]interface{}{}, nil)
|
||||
from, to := internal.GetTimeRangeFromDashboard(t, publicDashboard.Data)
|
||||
|
||||
service := &PublicDashboardServiceImpl{
|
||||
@@ -533,58 +587,167 @@ func TestBuildMetricRequest(t *testing.T) {
|
||||
|
||||
require.ErrorContains(t, err, ErrPublicDashboardPanelNotFound.Reason)
|
||||
})
|
||||
|
||||
t.Run("metric request built without hidden query", func(t *testing.T) {
|
||||
hiddenQuery := map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "mysql",
|
||||
"uid": "ds1",
|
||||
},
|
||||
"hide": true,
|
||||
"refId": "A",
|
||||
}
|
||||
nonHiddenQuery := map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "ds2",
|
||||
},
|
||||
"refId": "B",
|
||||
}
|
||||
|
||||
customPanels := []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"datasource": map[string]interface{}{
|
||||
"uid": "ds1",
|
||||
},
|
||||
"targets": []interface{}{hiddenQuery, nonHiddenQuery},
|
||||
}}
|
||||
|
||||
publicDashboard := insertTestDashboard(t, dashboardStore, "testDashWithHiddenQuery", 1, 0, true, []map[string]interface{}{}, customPanels)
|
||||
|
||||
reqDTO, err := service.buildMetricRequest(
|
||||
context.Background(),
|
||||
publicDashboard,
|
||||
publicDashboardPD,
|
||||
1,
|
||||
publicDashboardQueryDTO,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, from, reqDTO.From)
|
||||
require.Equal(t, to, reqDTO.To)
|
||||
|
||||
for i := range reqDTO.Queries {
|
||||
require.Equal(t, publicDashboardQueryDTO.IntervalMs, reqDTO.Queries[i].Get("intervalMs").MustInt64())
|
||||
require.Equal(t, publicDashboardQueryDTO.MaxDataPoints, reqDTO.Queries[i].Get("maxDataPoints").MustInt64())
|
||||
}
|
||||
|
||||
require.Len(t, reqDTO.Queries, 1)
|
||||
|
||||
require.NotEqual(
|
||||
t,
|
||||
simplejson.NewFromAny(hiddenQuery),
|
||||
reqDTO.Queries[0],
|
||||
)
|
||||
|
||||
require.Equal(
|
||||
t,
|
||||
simplejson.NewFromAny(nonHiddenQuery),
|
||||
reqDTO.Queries[0],
|
||||
)
|
||||
})
|
||||
|
||||
t.Run("metric request built with 0 queries len when all queries are hidden", func(t *testing.T) {
|
||||
customPanels := []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"datasource": map[string]interface{}{
|
||||
"uid": "ds1",
|
||||
},
|
||||
"targets": []interface{}{map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "mysql",
|
||||
"uid": "ds1",
|
||||
},
|
||||
"hide": true,
|
||||
"refId": "A",
|
||||
}, map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "ds2",
|
||||
},
|
||||
"hide": true,
|
||||
"refId": "B",
|
||||
}},
|
||||
}}
|
||||
|
||||
publicDashboard := insertTestDashboard(t, dashboardStore, "testDashWithAllQueriesHidden", 1, 0, true, []map[string]interface{}{}, customPanels)
|
||||
|
||||
reqDTO, err := service.buildMetricRequest(
|
||||
context.Background(),
|
||||
publicDashboard,
|
||||
publicDashboardPD,
|
||||
1,
|
||||
publicDashboardQueryDTO,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, from, reqDTO.From)
|
||||
require.Equal(t, to, reqDTO.To)
|
||||
|
||||
require.Len(t, reqDTO.Queries, 0)
|
||||
})
|
||||
}
|
||||
|
||||
func insertTestDashboard(t *testing.T, dashboardStore *dashboardsDB.DashboardStore, title string, orgId int64,
|
||||
folderId int64, isFolder bool, templateVars []map[string]interface{}, tags ...interface{}) *models.Dashboard {
|
||||
folderId int64, isFolder bool, templateVars []map[string]interface{}, customPanels []interface{}, tags ...interface{}) *models.Dashboard {
|
||||
t.Helper()
|
||||
|
||||
var dashboardPanels []interface{}
|
||||
if customPanels != nil {
|
||||
dashboardPanels = customPanels
|
||||
} else {
|
||||
dashboardPanels = []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"datasource": map[string]interface{}{
|
||||
"uid": "ds1",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "mysql",
|
||||
"uid": "ds1",
|
||||
},
|
||||
"refId": "A",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "ds2",
|
||||
},
|
||||
"refId": "B",
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": 2,
|
||||
"datasource": map[string]interface{}{
|
||||
"uid": "ds3",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "mysql",
|
||||
"uid": "ds3",
|
||||
},
|
||||
"refId": "C",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
cmd := models.SaveDashboardCommand{
|
||||
OrgId: orgId,
|
||||
FolderId: folderId,
|
||||
IsFolder: isFolder,
|
||||
Dashboard: simplejson.NewFromAny(map[string]interface{}{
|
||||
"id": nil,
|
||||
"title": title,
|
||||
"tags": tags,
|
||||
"panels": []interface{}{
|
||||
map[string]interface{}{
|
||||
"id": 1,
|
||||
"datasource": map[string]interface{}{
|
||||
"uid": "ds1",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "mysql",
|
||||
"uid": "ds1",
|
||||
},
|
||||
"refId": "A",
|
||||
},
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "prometheus",
|
||||
"uid": "ds2",
|
||||
},
|
||||
"refId": "B",
|
||||
},
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"id": 2,
|
||||
"datasource": map[string]interface{}{
|
||||
"uid": "ds3",
|
||||
},
|
||||
"targets": []interface{}{
|
||||
map[string]interface{}{
|
||||
"datasource": map[string]interface{}{
|
||||
"type": "mysql",
|
||||
"uid": "ds3",
|
||||
},
|
||||
"refId": "C",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"id": nil,
|
||||
"title": title,
|
||||
"tags": tags,
|
||||
"panels": dashboardPanels,
|
||||
"templating": map[string]interface{}{
|
||||
"list": templateVars,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user