Start of dashboard query API (#49547)
This PR adds endpoints for public dashboards to retrieve data from the backend (trusted) query engine. It works by executing queries defined on the backend without any user input and does not support template variables. * Public dashboard query API * Create new API on service for building metric request * Flesh out testing, implement BuildPublicDashboardMetricRequest * Test for errors and missing panels * Refactor tests, add supporting code for multiple datasources * Handle queries from multiple datasources * Explicitly pass no user for querying public dashboard Co-authored-by: Jeff Levin <jeff@levinology.com>
This commit is contained in:
co-authored by
Jeff Levin
parent
07aa2bbbba
commit
0371884cdd
@@ -27,3 +27,23 @@ func GetQueriesFromDashboard(dashboard *simplejson.Json) map[int64][]*simplejson
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func GroupQueriesByDataSource(queries []*simplejson.Json) (result [][]*simplejson.Json) {
|
||||
byDataSource := make(map[string][]*simplejson.Json)
|
||||
|
||||
for _, query := range queries {
|
||||
dataSourceUid, err := query.GetPath("datasource", "uid").String()
|
||||
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
byDataSource[dataSourceUid] = append(byDataSource[dataSourceUid], query)
|
||||
}
|
||||
|
||||
for _, queries := range byDataSource {
|
||||
result = append(result, queries)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -36,6 +36,17 @@ const (
|
||||
"interval": "",
|
||||
"legendFormat": "",
|
||||
"refId": "A"
|
||||
},
|
||||
{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "promds2"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "query2",
|
||||
"interval": "",
|
||||
"legendFormat": "",
|
||||
"refId": "B"
|
||||
}
|
||||
],
|
||||
"title": "Panel Title",
|
||||
@@ -94,7 +105,7 @@ func TestGetQueriesFromDashboard(t *testing.T) {
|
||||
queries := GetQueriesFromDashboard(json)
|
||||
require.Len(t, queries, 1)
|
||||
require.Contains(t, queries, int64(2))
|
||||
require.Len(t, queries[2], 1)
|
||||
require.Len(t, queries[2], 2)
|
||||
query, err := queries[2][0].MarshalJSON()
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(t, `{
|
||||
@@ -108,6 +119,19 @@ func TestGetQueriesFromDashboard(t *testing.T) {
|
||||
"legendFormat": "",
|
||||
"refId": "A"
|
||||
}`, string(query))
|
||||
query, err = queries[2][1].MarshalJSON()
|
||||
require.NoError(t, err)
|
||||
require.JSONEq(t, `{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "promds2"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "query2",
|
||||
"interval": "",
|
||||
"legendFormat": "",
|
||||
"refId": "B"
|
||||
}`, string(query))
|
||||
})
|
||||
|
||||
t.Run("can extract queries from old-style panels", func(t *testing.T) {
|
||||
@@ -130,3 +154,57 @@ func TestGetQueriesFromDashboard(t *testing.T) {
|
||||
}`, string(query))
|
||||
})
|
||||
}
|
||||
|
||||
func TestGroupQueriesByDataSource(t *testing.T) {
|
||||
t.Run("can divide queries by datasource", func(t *testing.T) {
|
||||
queries := []*simplejson.Json{
|
||||
simplejson.MustJson([]byte(`{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "_yxMP8Ynk"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "go_goroutines{job=\"$job\"}",
|
||||
"interval": "",
|
||||
"legendFormat": "",
|
||||
"refId": "A"
|
||||
}`)),
|
||||
simplejson.MustJson([]byte(`{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "promds2"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "query2",
|
||||
"interval": "",
|
||||
"legendFormat": "",
|
||||
"refId": "B"
|
||||
}`)),
|
||||
}
|
||||
|
||||
queriesByDatasource := GroupQueriesByDataSource(queries)
|
||||
require.Len(t, queriesByDatasource, 2)
|
||||
require.Contains(t, queriesByDatasource, []*simplejson.Json{simplejson.MustJson([]byte(`{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "_yxMP8Ynk"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "go_goroutines{job=\"$job\"}",
|
||||
"interval": "",
|
||||
"legendFormat": "",
|
||||
"refId": "A"
|
||||
}`))})
|
||||
require.Contains(t, queriesByDatasource, []*simplejson.Json{simplejson.MustJson([]byte(`{
|
||||
"datasource": {
|
||||
"type": "prometheus",
|
||||
"uid": "promds2"
|
||||
},
|
||||
"exemplar": true,
|
||||
"expr": "query2",
|
||||
"interval": "",
|
||||
"legendFormat": "",
|
||||
"refId": "B"
|
||||
}`))})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,6 +10,11 @@ var (
|
||||
StatusCode: 404,
|
||||
Status: "not-found",
|
||||
}
|
||||
ErrPublicDashboardPanelNotFound = DashboardErr{
|
||||
Reason: "Panel not found in dashboard",
|
||||
StatusCode: 404,
|
||||
Status: "not-found",
|
||||
}
|
||||
ErrPublicDashboardIdentifierNotSet = DashboardErr{
|
||||
Reason: "No Uid for public dashboard specified",
|
||||
StatusCode: 400,
|
||||
|
||||
Reference in New Issue
Block a user