Plugins: Refactor plugin dashboards (#44315)

Moves/refactor Grafana specific functionality related to plugin dashboards 
out to specific services for importing dashboards and keep app plugin dashboards
up-to-date.

Fixes #44257
This commit is contained in:
Marcus Efraimsson
2022-01-28 10:28:33 +01:00
committed by GitHub
parent 7e26dbb5ff
commit 94edd7a762
24 changed files with 1814 additions and 319 deletions
-1
View File
@@ -342,7 +342,6 @@ func (hs *HTTPServer) registerRoutes() {
dashboardRoute.Post("/db", routing.Wrap(hs.PostDashboard))
dashboardRoute.Get("/home", routing.Wrap(hs.GetHomeDashboard))
dashboardRoute.Get("/tags", GetDashboardTags)
dashboardRoute.Post("/import", routing.Wrap(hs.ImportDashboard))
dashboardRoute.Group("/id/:dashboardId", func(dashIdRoute routing.RouteRegister) {
dashIdRoute.Get("/versions", routing.Wrap(GetDashboardVersions))
+49
View File
@@ -0,0 +1,49 @@
package apierrors
import (
"context"
"errors"
"fmt"
"net/http"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/alerting"
"github.com/grafana/grafana/pkg/util"
)
// ToDashboardErrorResponse returns a different response status according to the dashboard error type
func ToDashboardErrorResponse(ctx context.Context, pluginStore plugins.Store, err error) response.Response {
var dashboardErr models.DashboardErr
if ok := errors.As(err, &dashboardErr); ok {
if body := dashboardErr.Body(); body != nil {
return response.JSON(dashboardErr.StatusCode, body)
}
if dashboardErr.StatusCode != http.StatusBadRequest {
return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), err)
}
return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), nil)
}
if errors.Is(err, models.ErrFolderNotFound) {
return response.Error(http.StatusBadRequest, err.Error(), nil)
}
var validationErr alerting.ValidationError
if ok := errors.As(err, &validationErr); ok {
return response.Error(http.StatusUnprocessableEntity, validationErr.Error(), err)
}
var pluginErr models.UpdatePluginDashboardError
if ok := errors.As(err, &pluginErr); ok {
message := fmt.Sprintf("The dashboard belongs to plugin %s.", pluginErr.PluginId)
// look up plugin name
if plugin, exists := pluginStore.Plugin(ctx, pluginErr.PluginId); exists {
message = fmt.Sprintf("The dashboard belongs to plugin %s.", plugin.Name)
}
return response.JSON(http.StatusPreconditionFailed, util.DynMap{"status": "plugin-dashboard", "message": message})
}
return response.Error(http.StatusInternalServerError, "Failed to save dashboard", err)
}
+2 -35
View File
@@ -10,6 +10,7 @@ import (
"path/filepath"
"strconv"
"github.com/grafana/grafana/pkg/api/apierrors"
"github.com/grafana/grafana/pkg/api/dtos"
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus"
@@ -381,7 +382,7 @@ func (hs *HTTPServer) postDashboard(c *models.ReqContext, cmd models.SaveDashboa
}
if err != nil {
return hs.dashboardSaveErrorToApiResponse(ctx, err)
return apierrors.ToDashboardErrorResponse(ctx, hs.pluginStore, err)
}
if hs.Cfg.EditorsCanAdmin && newDashboard {
@@ -409,40 +410,6 @@ func (hs *HTTPServer) postDashboard(c *models.ReqContext, cmd models.SaveDashboa
})
}
func (hs *HTTPServer) dashboardSaveErrorToApiResponse(ctx context.Context, err error) response.Response {
var dashboardErr models.DashboardErr
if ok := errors.As(err, &dashboardErr); ok {
if body := dashboardErr.Body(); body != nil {
return response.JSON(dashboardErr.StatusCode, body)
}
if dashboardErr.StatusCode != 400 {
return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), err)
}
return response.Error(dashboardErr.StatusCode, dashboardErr.Error(), nil)
}
if errors.Is(err, models.ErrFolderNotFound) {
return response.Error(400, err.Error(), nil)
}
var validationErr alerting.ValidationError
if ok := errors.As(err, &validationErr); ok {
return response.Error(422, validationErr.Error(), err)
}
var pluginErr models.UpdatePluginDashboardError
if ok := errors.As(err, &pluginErr); ok {
message := fmt.Sprintf("The dashboard belongs to plugin %s.", pluginErr.PluginId)
// look up plugin name
if plugin, exists := hs.pluginStore.Plugin(ctx, pluginErr.PluginId); exists {
message = fmt.Sprintf("The dashboard belongs to plugin %s.", plugin.Name)
}
return response.JSON(412, util.DynMap{"status": "plugin-dashboard", "message": message})
}
return response.Error(500, "Failed to save dashboard", err)
}
// GetHomeDashboard returns the home dashboard.
func (hs *HTTPServer) GetHomeDashboard(c *models.ReqContext) response.Response {
prefsQuery := models.GetPreferencesWithDefaultsQuery{User: c.SignedInUser}
-11
View File
@@ -1,7 +1,6 @@
package dtos
import (
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/plugins"
)
@@ -59,16 +58,6 @@ func (slice PluginList) Swap(i, j int) {
slice[i], slice[j] = slice[j], slice[i]
}
type ImportDashboardCommand struct {
PluginId string `json:"pluginId"`
Path string `json:"path"`
Overwrite bool `json:"overwrite"`
Dashboard *simplejson.Json `json:"dashboard"`
Inputs []plugins.ImportDashboardInput `json:"inputs"`
FolderId int64 `json:"folderId"`
FolderUid string `json:"folderUid"`
}
type InstallPluginCommand struct {
Version string `json:"version"`
}
-45
View File
@@ -217,51 +217,6 @@ func (hs *HTTPServer) GetPluginMarkdown(c *models.ReqContext) response.Response
return resp
}
func (hs *HTTPServer) ImportDashboard(c *models.ReqContext) response.Response {
apiCmd := dtos.ImportDashboardCommand{}
if err := web.Bind(c.Req, &apiCmd); err != nil {
return response.Error(http.StatusBadRequest, "bad request data", err)
}
var err error
if apiCmd.PluginId == "" && apiCmd.Dashboard == nil {
return response.Error(422, "Dashboard must be set", nil)
}
limitReached, err := hs.QuotaService.QuotaReached(c, "dashboard")
if err != nil {
return response.Error(500, "failed to get quota", err)
}
if limitReached {
return response.Error(403, "Quota reached", nil)
}
trimDefaults := c.QueryBoolWithDefault("trimdefaults", true)
if trimDefaults && !hs.LoadSchemaService.IsDisabled() {
apiCmd.Dashboard, err = hs.LoadSchemaService.DashboardApplyDefaults(apiCmd.Dashboard)
if err != nil {
return response.Error(500, "Error while applying default value to the dashboard json", err)
}
}
dashInfo, dash, err := hs.pluginDashboardManager.ImportDashboard(c.Req.Context(), apiCmd.PluginId, apiCmd.Path, c.OrgId, apiCmd.FolderId,
apiCmd.Dashboard, apiCmd.Overwrite, apiCmd.Inputs, c.SignedInUser)
if err != nil {
return hs.dashboardSaveErrorToApiResponse(c.Req.Context(), err)
}
err = hs.LibraryPanelService.ImportLibraryPanelsForDashboard(c.Req.Context(), c.SignedInUser, dash, apiCmd.FolderId)
if err != nil {
return response.Error(500, "Error while importing library panels", err)
}
err = hs.LibraryPanelService.ConnectLibraryPanelsForDashboard(c.Req.Context(), c.SignedInUser, dash)
if err != nil {
return response.Error(500, "Error while connecting library panels", err)
}
return response.JSON(200, dashInfo)
}
// CollectPluginMetrics collect metrics from a plugin.
//
// /api/plugins/:pluginId/metrics