Search: Make the existing dashboard parsing code public (#95649)

This commit is contained in:
Ryan McKinley 2024-11-06 07:35:15 +03:00 committed by GitHub
parent ed52515ae3
commit 7f560c13e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 248 additions and 35 deletions

View File

@ -112,12 +112,15 @@ func newDatasourceVariableLookup(dsLookup DatasourceLookup) *datasourceVariableL
}
}
// nolint:gocyclo
// ReadDashboard will take a byte stream and return dashboard info
func readDashboard(stream io.Reader, lookup DatasourceLookup) (*dashboardInfo, error) {
dash := &dashboardInfo{}
func ReadDashboard(stream io.Reader, lookup DatasourceLookup) (*DashboardSummaryInfo, error) {
iter := jsoniter.Parse(jsoniter.ConfigDefault, stream, 1024)
return readDashboardIter(iter, lookup)
}
// nolint:gocyclo
func readDashboardIter(iter *jsoniter.Iterator, lookup DatasourceLookup) (*DashboardSummaryInfo, error) {
dash := &DashboardSummaryInfo{}
datasourceVariablesLookup := newDatasourceVariableLookup(lookup)
@ -129,6 +132,14 @@ func readDashboard(stream io.Reader, lookup DatasourceLookup) (*dashboardInfo, e
}
switch l1Field {
// k8s metadata wrappers (skip)
case "metadata", "kind", "apiVersion":
_ = iter.Read()
// recursively read the spec as dashboard json
case "spec":
return readDashboardIter(iter, lookup)
case "id":
dash.ID = iter.ReadInt64()
@ -268,7 +279,12 @@ func readDashboard(stream io.Reader, lookup DatasourceLookup) (*dashboardInfo, e
filterOutSpecialDatasources(dash)
targets := newTargetInfo(lookup)
for _, panel := range dash.Panels {
for idx, panel := range dash.Panels {
if panel.Type == "row" {
dash.Panels[idx].Datasource = nil
continue
}
targets.addPanel(panel)
}
dash.Datasource = targets.GetDatasourceInfo()
@ -276,13 +292,13 @@ func readDashboard(stream io.Reader, lookup DatasourceLookup) (*dashboardInfo, e
return dash, iter.Error
}
func panelRequiresDatasource(panel panelInfo) bool {
func panelRequiresDatasource(panel PanelSummaryInfo) bool {
return panel.Type != "row"
}
func fillDefaultDatasources(dash *dashboardInfo, lookup DatasourceLookup) {
func fillDefaultDatasources(dash *DashboardSummaryInfo, lookup DatasourceLookup) {
for i, panel := range dash.Panels {
if len(panel.Datasource) != 0 || !panelRequiresDatasource(panel) {
if len(panel.Datasource) != 0 || !panelRequiresDatasource(PanelSummaryInfo{}) {
continue
}
@ -293,7 +309,7 @@ func fillDefaultDatasources(dash *dashboardInfo, lookup DatasourceLookup) {
}
}
func filterOutSpecialDatasources(dash *dashboardInfo) {
func filterOutSpecialDatasources(dash *DashboardSummaryInfo) {
for i, panel := range dash.Panels {
var dsRefs []DataSourceRef
@ -315,7 +331,7 @@ func filterOutSpecialDatasources(dash *dashboardInfo) {
}
}
func replaceDatasourceVariables(dash *dashboardInfo, datasourceVariablesLookup *datasourceVariableLookup) {
func replaceDatasourceVariables(dash *DashboardSummaryInfo, datasourceVariablesLookup *datasourceVariableLookup) {
for i, panel := range dash.Panels {
var dsVariableRefs []DataSourceRef
var dsRefs []DataSourceRef
@ -362,8 +378,8 @@ func findDatasourceRefsForVariables(dsVariableRefs []DataSourceRef, datasourceVa
}
// will always return strings for now
func readpanelInfo(iter *jsoniter.Iterator, lookup DatasourceLookup) panelInfo {
panel := panelInfo{}
func readpanelInfo(iter *jsoniter.Iterator, lookup DatasourceLookup) PanelSummaryInfo {
panel := PanelSummaryInfo{}
targets := newTargetInfo(lookup)

View File

@ -71,6 +71,7 @@ func TestReadDashboard(t *testing.T) {
"special-datasource-types",
"panels-without-datasources",
"panel-with-library-panel-field",
"k8s-wrapper",
}
devdash := "../../../../../devenv/dev-dashboards/"
@ -89,7 +90,7 @@ func TestReadDashboard(t *testing.T) {
}
require.NoError(t, err)
dash, err := readDashboard(f, dsLookupForTests())
dash, err := ReadDashboard(f, dsLookupForTests())
sortDatasources(dash)
require.NoError(t, err)
@ -114,7 +115,7 @@ func TestReadDashboard(t *testing.T) {
}
// assure consistent ordering of datasources to prevent random failures of `assert.JSONEq`
func sortDatasources(dash *dashboardInfo) {
func sortDatasources(dash *DashboardSummaryInfo) {
sort.Slice(dash.Datasource, func(i, j int) bool {
return strings.Compare(dash.Datasource[i].UID, dash.Datasource[j].UID) > 0
})

View File

@ -40,7 +40,7 @@ func NewStaticDashboardSummaryBuilder(lookup DatasourceLookup, sanitize bool) en
Fields: make(map[string]string),
}
stream := bytes.NewBuffer(body)
dash, err := readDashboard(stream, lookup)
dash, err := ReadDashboard(stream, lookup)
if err != nil {
summary.Error = &entity.EntityErrorInfo{
Message: err.Error(),
@ -74,7 +74,7 @@ func NewStaticDashboardSummaryBuilder(lookup DatasourceLookup, sanitize bool) en
}
// panelSummary take panel info and returns entity summaries for the given panel and all its collapsed panels.
func panelSummary(panel panelInfo, uid string, dashboardRefs ReferenceAccumulator) []*entity.EntitySummary {
func panelSummary(panel PanelSummaryInfo, uid string, dashboardRefs ReferenceAccumulator) []*entity.EntitySummary {
panels := []*entity.EntitySummary{}
panelRefs := NewReferenceAccumulator()

View File

@ -82,7 +82,7 @@ func (s *targetInfo) addTarget(iter *jsoniter.Iterator) {
}
}
func (s *targetInfo) addPanel(panel panelInfo) {
func (s *targetInfo) addPanel(panel PanelSummaryInfo) {
for idx, v := range panel.Datasource {
if v.UID != "" {
s.uids[v.UID] = &panel.Datasource[idx]

View File

@ -0,0 +1,74 @@
{
"id": 141,
"title": "pppp",
"tags": null,
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
],
"panels": [
{
"id": 1,
"title": "green pie",
"libraryPanel": "a7975b7a-fb53-4ab7-951d-15810953b54f",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 2,
"title": "green pie",
"libraryPanel": "e1d5f519-dabd-47c6-9ad7-83d181ce1cee",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 7,
"title": "",
"type": "barchart",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 8,
"title": "",
"type": "graph",
"datasource": [
{
"uid": "default.uid",
"type": "default.type"
}
]
},
{
"id": 3,
"title": "collapsed row",
"type": "row",
"collapsed": [
{
"id": 42,
"title": "blue pie",
"libraryPanel": "l3d2s634-fdgf-75u4-3fg3-67j966ii7jur"
}
]
}
],
"schemaVersion": 38,
"linkCount": 0,
"timeFrom": "now-6h",
"timeTo": "now",
"timezone": ""
}

View File

@ -0,0 +1,122 @@
{
"kind": "Dashboard",
"apiVersion": "dashboard.grafana.app/v0alpha1",
"metadata": {
"name": "adfbg6f",
"namespace": "default",
"uid": "b396894e-56bf-4a01-837b-64157912ca00",
"creationTimestamp": "2024-10-30T18:30:54Z",
"annotations": {
"grafana.app/createdBy": "user:be2g71ke8yoe8b",
"grafana.app/originHash": "Grafana v9.2.0 (NA)",
"grafana.app/originName": "UI",
"grafana.app/originPath": "/dashboard/new"
}
},
"spec": {
"annotations": {
"list": [
{
"builtIn": 1,
"datasource": {
"type": "grafana",
"uid": "-- Grafana --"
},
"enable": true,
"hide": true,
"iconColor": "rgba(0, 211, 255, 1)",
"name": "Annotations & Alerts",
"type": "dashboard"
}
]
},
"editable": true,
"fiscalYearStartMonth": 0,
"graphTooltip": 0,
"id": 141,
"links": [],
"liveNow": false,
"panels": [
{
"gridPos": {
"h": 8,
"w": 12,
"x": 0,
"y": 0
},
"id": 1,
"libraryPanel": {
"name": "green pie",
"uid": "a7975b7a-fb53-4ab7-951d-15810953b54f"
},
"title": "green pie"
},
{
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"id": 2,
"libraryPanel": {
"name": "red pie",
"uid": "e1d5f519-dabd-47c6-9ad7-83d181ce1cee"
},
"title": "green pie"
},
{
"id": 7,
"type": "barchart"
},
{
"id": 8,
"type": "graph"
},
{
"collapsed": true,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
"y": 9
},
"id": 3,
"panels": [
{
"gridPos": {
"h": 8,
"w": 12,
"x": 12,
"y": 0
},
"id": 42,
"libraryPanel": {
"name": "blue pie",
"uid": "l3d2s634-fdgf-75u4-3fg3-67j966ii7jur"
},
"title": "blue pie"
}
],
"title": "collapsed row",
"type": "row"
}
],
"refresh": "",
"schemaVersion": 38,
"tags": [],
"templating": {
"list": []
},
"time": {
"from": "now-6h",
"to": "now"
},
"timepicker": {},
"timezone": "",
"title": "pppp",
"uid": "adfbg6f",
"version": 3,
"weekStart": ""
}
}

View File

@ -1,6 +1,6 @@
package dashboard
type panelInfo struct {
type PanelSummaryInfo struct {
ID int64 `json:"id"`
Title string `json:"title"`
Description string `json:"description,omitempty"`
@ -10,23 +10,23 @@ type panelInfo struct {
Datasource []DataSourceRef `json:"datasource,omitempty"` // UIDs
Transformer []string `json:"transformer,omitempty"` // ids of the transformation steps
// Rows define panels as sub objects
Collapsed []panelInfo `json:"collapsed,omitempty"`
Collapsed []PanelSummaryInfo `json:"collapsed,omitempty"`
}
type dashboardInfo struct {
UID string `json:"uid,omitempty"`
ID int64 `json:"id,omitempty"` // internal ID
Title string `json:"title"`
Description string `json:"description,omitempty"`
Tags []string `json:"tags"`
TemplateVars []string `json:"templateVars,omitempty"` // the keys used
Datasource []DataSourceRef `json:"datasource,omitempty"` // UIDs
Panels []panelInfo `json:"panels"` // nesed documents
SchemaVersion int64 `json:"schemaVersion"`
LinkCount int64 `json:"linkCount"`
TimeFrom string `json:"timeFrom"`
TimeTo string `json:"timeTo"`
TimeZone string `json:"timezone"`
Refresh string `json:"refresh,omitempty"`
ReadOnly bool `json:"readOnly,omitempty"` // editable = false
type DashboardSummaryInfo struct {
UID string `json:"uid,omitempty"`
ID int64 `json:"id,omitempty"` // internal ID
Title string `json:"title"`
Description string `json:"description,omitempty"`
Tags []string `json:"tags"`
TemplateVars []string `json:"templateVars,omitempty"` // the keys used
Datasource []DataSourceRef `json:"datasource,omitempty"` // UIDs
Panels []PanelSummaryInfo `json:"panels"` // nesed documents
SchemaVersion int64 `json:"schemaVersion"`
LinkCount int64 `json:"linkCount"`
TimeFrom string `json:"timeFrom"`
TimeTo string `json:"timeTo"`
TimeZone string `json:"timezone"`
Refresh string `json:"refresh,omitempty"`
ReadOnly bool `json:"readOnly,omitempty"` // editable = false
}