Dashboard Imports: Fix creating new library panels (#107219)

pull/107244/head
Stephanie Hingtgen 2 days ago committed by GitHub
parent 88d113f37c
commit f8189eece9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 22
      pkg/services/dashboardimport/service/service.go
  2. 3
      pkg/services/dashboardimport/service/service_test.go
  3. 211
      pkg/tests/api/dashboards/api_dashboards_test.go

@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/services/dashboardimport/api" "github.com/grafana/grafana/pkg/services/dashboardimport/api"
"github.com/grafana/grafana/pkg/services/dashboardimport/utils" "github.com/grafana/grafana/pkg/services/dashboardimport/utils"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/librarypanels" "github.com/grafana/grafana/pkg/services/librarypanels"
"github.com/grafana/grafana/pkg/services/plugindashboards" "github.com/grafana/grafana/pkg/services/plugindashboards"
@ -23,13 +24,14 @@ func ProvideService(routeRegister routing.RouteRegister,
quotaService quota.Service, quotaService quota.Service,
pluginDashboardService plugindashboards.Service, pluginStore pluginstore.Store, pluginDashboardService plugindashboards.Service, pluginStore pluginstore.Store,
libraryPanelService librarypanels.Service, dashboardService dashboards.DashboardService, libraryPanelService librarypanels.Service, dashboardService dashboards.DashboardService,
ac accesscontrol.AccessControl, folderService folder.Service, ac accesscontrol.AccessControl, folderService folder.Service, features featuremgmt.FeatureToggles,
) *ImportDashboardService { ) *ImportDashboardService {
s := &ImportDashboardService{ s := &ImportDashboardService{
pluginDashboardService: pluginDashboardService, pluginDashboardService: pluginDashboardService,
dashboardService: dashboardService, dashboardService: dashboardService,
libraryPanelService: libraryPanelService, libraryPanelService: libraryPanelService,
folderService: folderService, folderService: folderService,
features: features,
} }
dashboardImportAPI := api.New(s, quotaService, pluginStore, ac) dashboardImportAPI := api.New(s, quotaService, pluginStore, ac)
@ -43,6 +45,7 @@ type ImportDashboardService struct {
dashboardService dashboards.DashboardService dashboardService dashboards.DashboardService
libraryPanelService librarypanels.Service libraryPanelService librarypanels.Service
folderService folder.Service folderService folder.Service
features featuremgmt.FeatureToggles
} }
func (s *ImportDashboardService) ImportDashboard(ctx context.Context, req *dashboardimport.ImportDashboardRequest) (*dashboardimport.ImportDashboardResponse, error) { func (s *ImportDashboardService) ImportDashboard(ctx context.Context, req *dashboardimport.ImportDashboardRequest) (*dashboardimport.ImportDashboardResponse, error) {
@ -131,22 +134,25 @@ func (s *ImportDashboardService) ImportDashboard(ctx context.Context, req *dashb
User: req.User, User: req.User,
} }
savedDashboard, err := s.dashboardService.ImportDashboard(ctx, dto)
if err != nil {
return nil, err
}
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.DashboardImport).Inc()
// nolint:staticcheck // nolint:staticcheck
err = s.libraryPanelService.ImportLibraryPanelsForDashboard(ctx, req.User, libraryElements, generatedDash.Get("panels").MustArray(), req.FolderId, req.FolderUid) err = s.libraryPanelService.ImportLibraryPanelsForDashboard(ctx, req.User, libraryElements, generatedDash.Get("panels").MustArray(), req.FolderId, req.FolderUid)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = s.libraryPanelService.ConnectLibraryPanelsForDashboard(ctx, req.User, savedDashboard) savedDashboard, err := s.dashboardService.ImportDashboard(ctx, dto)
if err != nil { if err != nil {
return nil, err return nil, err
} }
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.DashboardImport).Inc()
// in the k8s flow, we connect the library panels in pkg/registry/apis/dashboard/legacy/sql_dashboards.go
if !s.features.IsEnabledGlobally(featuremgmt.FlagKubernetesClientDashboardsFolders) {
err = s.libraryPanelService.ConnectLibraryPanelsForDashboard(ctx, req.User, savedDashboard)
if err != nil {
return nil, err
}
}
revision := savedDashboard.Data.Get("revision").MustInt64(0) revision := savedDashboard.Data.Get("revision").MustInt64(0)
metrics.MFolderIDsServiceCount.WithLabelValues(metrics.DashboardImport).Inc() metrics.MFolderIDsServiceCount.WithLabelValues(metrics.DashboardImport).Inc()

@ -12,6 +12,7 @@ import (
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/services/dashboardimport" "github.com/grafana/grafana/pkg/services/dashboardimport"
"github.com/grafana/grafana/pkg/services/dashboards" "github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder" "github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/folder/foldertest" "github.com/grafana/grafana/pkg/services/folder/foldertest"
"github.com/grafana/grafana/pkg/services/librarypanels" "github.com/grafana/grafana/pkg/services/librarypanels"
@ -67,6 +68,7 @@ func TestImportDashboardService(t *testing.T) {
dashboardService: dashboardService, dashboardService: dashboardService,
libraryPanelService: libraryPanelService, libraryPanelService: libraryPanelService,
folderService: folderService, folderService: folderService,
features: featuremgmt.WithFeatures(),
} }
req := &dashboardimport.ImportDashboardRequest{ req := &dashboardimport.ImportDashboardRequest{
@ -127,6 +129,7 @@ func TestImportDashboardService(t *testing.T) {
dashboardService: dashboardService, dashboardService: dashboardService,
libraryPanelService: libraryPanelService, libraryPanelService: libraryPanelService,
folderService: folderService, folderService: folderService,
features: featuremgmt.WithFeatures(),
} }
loadResp, err := loadTestDashboard(context.Background(), &plugindashboards.LoadPluginDashboardRequest{ loadResp, err := loadTestDashboard(context.Background(), &plugindashboards.LoadPluginDashboardRequest{

@ -551,3 +551,214 @@ func testPreserveSchemaVersion(t *testing.T, featureToggles []string) {
}) })
} }
} }
func TestIntegrationImportDashboardWithLibraryPanels(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
testImportDashboardWithLibraryPanels(t, []string{})
}
func TestIntegrationImportDashboardWithLibraryPanelsK8s(t *testing.T) {
if testing.Short() {
t.Skip("skipping integration test")
}
testImportDashboardWithLibraryPanels(t, []string{featuremgmt.FlagKubernetesClientDashboardsFolders})
}
func testImportDashboardWithLibraryPanels(t *testing.T, featureToggles []string) {
dir, path := testinfra.CreateGrafDir(t, testinfra.GrafanaOpts{
DisableAnonymous: true,
EnableFeatureToggles: featureToggles,
})
grafanaListedAddr, _ := testinfra.StartGrafanaEnv(t, dir, path)
t.Run("import dashboard with library panels should create library panels and connections", func(t *testing.T) {
dashboardJSON := `{
"title": "Test Dashboard with Library Panels",
"panels": [
{
"id": 1,
"title": "Library Panel 1",
"type": "text",
"gridPos": {"h": 8, "w": 12, "x": 0, "y": 0},
"libraryPanel": {
"uid": "test-lib-panel-1",
"name": "Test Library Panel 1"
}
},
{
"id": 2,
"title": "Library Panel 2",
"type": "stat",
"gridPos": {"h": 8, "w": 12, "x": 12, "y": 0},
"libraryPanel": {
"uid": "test-lib-panel-2",
"name": "Test Library Panel 2"
}
}
],
"__elements": {
"test-lib-panel-1": {
"uid": "test-lib-panel-1",
"name": "Test Library Panel 1",
"kind": 1,
"type": "text",
"model": {
"title": "Test Library Panel 1",
"type": "text",
"options": {
"content": "This is a test library panel"
}
}
},
"test-lib-panel-2": {
"uid": "test-lib-panel-2",
"name": "Test Library Panel 2",
"kind": 1,
"type": "stat",
"model": {
"title": "Test Library Panel 2",
"type": "stat",
"options": {
"colorMode": "value",
"graphMode": "area",
"justifyMode": "auto",
"orientation": "auto",
"reduceOptions": {
"calcs": ["lastNotNull"],
"fields": "",
"values": false
},
"textMode": "auto"
},
"targets": [
{
"refId": "A",
"scenarioId": "csv_metric_values",
"stringInput": "1,20,90,30,5,0"
}
]
}
}
}
}`
data, err := simplejson.NewJson([]byte(dashboardJSON))
require.NoError(t, err)
buf := &bytes.Buffer{}
err = json.NewEncoder(buf).Encode(dashboardimport.ImportDashboardRequest{
Dashboard: data,
})
require.NoError(t, err)
u := fmt.Sprintf("http://admin:admin@%s/api/dashboards/import", grafanaListedAddr)
// nolint:gosec
resp, err := http.Post(u, "application/json", buf)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
b, err := io.ReadAll(resp.Body)
require.NoError(t, err)
var importResp struct {
UID string `json:"uid"`
}
err = json.Unmarshal(b, &importResp)
require.NoError(t, err)
require.NotEmpty(t, importResp.UID)
t.Run("library panels should be created", func(t *testing.T) {
url := fmt.Sprintf("http://admin:admin@%s/api/library-elements/test-lib-panel-1", grafanaListedAddr)
// nolint:gosec
resp, err := http.Get(url)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
panel, err := io.ReadAll(resp.Body)
require.NoError(t, err)
var panelRes struct {
Result struct {
UID string `json:"uid"`
Name string `json:"name"`
Type string `json:"type"`
} `json:"result"`
}
err = json.Unmarshal(panel, &panelRes)
require.NoError(t, err)
assert.Equal(t, "test-lib-panel-1", panelRes.Result.UID)
assert.Equal(t, "Test Library Panel 1", panelRes.Result.Name)
assert.Equal(t, "text", panelRes.Result.Type)
url = fmt.Sprintf("http://admin:admin@%s/api/library-elements/test-lib-panel-2", grafanaListedAddr)
// nolint:gosec
resp, err = http.Get(url)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode)
t.Cleanup(func() {
err := resp.Body.Close()
require.NoError(t, err)
})
panel, err = io.ReadAll(resp.Body)
require.NoError(t, err)
err = json.Unmarshal(panel, &panelRes)
require.NoError(t, err)
assert.Equal(t, "test-lib-panel-2", panelRes.Result.UID)
assert.Equal(t, "Test Library Panel 2", panelRes.Result.Name)
assert.Equal(t, "stat", panelRes.Result.Type)
})
t.Run("library panels should be connected to dashboard", func(t *testing.T) {
url := fmt.Sprintf("http://admin:admin@%s/api/library-elements/test-lib-panel-1/connections", grafanaListedAddr)
// nolint:gosec
connectionsResp, err := http.Get(url)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, connectionsResp.StatusCode)
t.Cleanup(func() {
err := connectionsResp.Body.Close()
require.NoError(t, err)
})
connections, err := io.ReadAll(connectionsResp.Body)
require.NoError(t, err)
var connectionsRes struct {
Result []struct {
ConnectionUID string `json:"connectionUid"`
} `json:"result"`
}
err = json.Unmarshal(connections, &connectionsRes)
require.NoError(t, err)
assert.Len(t, connectionsRes.Result, 1)
assert.Equal(t, importResp.UID, connectionsRes.Result[0].ConnectionUID)
url = fmt.Sprintf("http://admin:admin@%s/api/library-elements/test-lib-panel-2/connections", grafanaListedAddr)
// nolint:gosec
connectionsResp, err = http.Get(url)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, connectionsResp.StatusCode)
t.Cleanup(func() {
err := connectionsResp.Body.Close()
require.NoError(t, err)
})
connections, err = io.ReadAll(connectionsResp.Body)
require.NoError(t, err)
err = json.Unmarshal(connections, &connectionsRes)
require.NoError(t, err)
assert.Len(t, connectionsRes.Result, 1)
assert.Equal(t, importResp.UID, connectionsRes.Result[0].ConnectionUID)
})
})
}

Loading…
Cancel
Save