grafana/pkg/plugins/manager/dashboard_import.go
Arve Knudsen 87c3a2b790
PluginManager: Make Plugins, Renderer and DataSources non-global (#31866)
* PluginManager: Make Plugins and DataSources non-global

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix integration tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Replace outdated command

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* DashboardService: Ensure it gets constructed with necessary parameters

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix build

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* DashboardService: Ensure it gets constructed with necessary parameters

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Remove dead code

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix test

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix test

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Remove FocusConvey

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix test

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Remove dead code

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Undo interface changes

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Backend: Move tsdbifaces.RequestHandler to plugins.DataRequestHandler

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Rename to DataSourceCount

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Consolidate dashboard interfaces into one

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix test

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>

* Fix dashboard integration tests

Signed-off-by: Arve Knudsen <arve.knudsen@gmail.com>
2021-03-17 16:06:10 +01:00

163 lines
4.2 KiB
Go

package manager
import (
"encoding/json"
"fmt"
"regexp"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/services/dashboards"
)
var varRegex = regexp.MustCompile(`(\$\{.+?\})`)
type DashboardInputMissingError struct {
VariableName string
}
func (e DashboardInputMissingError) Error() string {
return fmt.Sprintf("Dashboard input variable: %v missing from import command", e.VariableName)
}
func (pm *PluginManager) ImportDashboard(pluginID, path string, orgID, folderID int64, dashboardModel *simplejson.Json,
overwrite bool, inputs []plugins.ImportDashboardInput, user *models.SignedInUser,
requestHandler plugins.DataRequestHandler) (plugins.PluginDashboardInfoDTO, error) {
var dashboard *models.Dashboard
if pluginID != "" {
var err error
if dashboard, err = pm.LoadPluginDashboard(pluginID, path); err != nil {
return plugins.PluginDashboardInfoDTO{}, err
}
} else {
dashboard = models.NewDashboardFromJson(dashboardModel)
}
evaluator := &DashTemplateEvaluator{
template: dashboard.Data,
inputs: inputs,
}
generatedDash, err := evaluator.Eval()
if err != nil {
return plugins.PluginDashboardInfoDTO{}, err
}
saveCmd := models.SaveDashboardCommand{
Dashboard: generatedDash,
OrgId: orgID,
UserId: user.UserId,
Overwrite: overwrite,
PluginId: pluginID,
FolderId: folderID,
}
dto := &dashboards.SaveDashboardDTO{
OrgId: orgID,
Dashboard: saveCmd.GetDashboardModel(),
Overwrite: saveCmd.Overwrite,
User: user,
}
savedDash, err := dashboards.NewService(pm.SQLStore).ImportDashboard(dto)
if err != nil {
return plugins.PluginDashboardInfoDTO{}, err
}
return plugins.PluginDashboardInfoDTO{
PluginId: pluginID,
Title: savedDash.Title,
Path: path,
Revision: savedDash.Data.Get("revision").MustInt64(1),
FolderId: savedDash.FolderId,
ImportedUri: "db/" + savedDash.Slug,
ImportedUrl: savedDash.GetUrl(),
ImportedRevision: dashboard.Data.Get("revision").MustInt64(1),
Imported: true,
DashboardId: savedDash.Id,
Slug: savedDash.Slug,
}, nil
}
type DashTemplateEvaluator struct {
template *simplejson.Json
inputs []plugins.ImportDashboardInput
variables map[string]string
result *simplejson.Json
}
func (e *DashTemplateEvaluator) findInput(varName string, varType string) *plugins.ImportDashboardInput {
for _, input := range e.inputs {
if varType == input.Type && (input.Name == varName || input.Name == "*") {
return &input
}
}
return nil
}
func (e *DashTemplateEvaluator) Eval() (*simplejson.Json, error) {
e.result = simplejson.New()
e.variables = make(map[string]string)
// check that we have all inputs we need
for _, inputDef := range e.template.Get("__inputs").MustArray() {
inputDefJson := simplejson.NewFromAny(inputDef)
inputName := inputDefJson.Get("name").MustString()
inputType := inputDefJson.Get("type").MustString()
input := e.findInput(inputName, inputType)
if input == nil {
return nil, &DashboardInputMissingError{VariableName: inputName}
}
e.variables["${"+inputName+"}"] = input.Value
}
return simplejson.NewFromAny(e.evalObject(e.template)), nil
}
func (e *DashTemplateEvaluator) evalValue(source *simplejson.Json) interface{} {
sourceValue := source.Interface()
switch v := sourceValue.(type) {
case string:
interpolated := varRegex.ReplaceAllStringFunc(v, func(match string) string {
replacement, exists := e.variables[match]
if exists {
return replacement
}
return match
})
return interpolated
case bool:
return v
case json.Number:
return v
case map[string]interface{}:
return e.evalObject(source)
case []interface{}:
array := make([]interface{}, 0)
for _, item := range v {
array = append(array, e.evalValue(simplejson.NewFromAny(item)))
}
return array
}
return nil
}
func (e *DashTemplateEvaluator) evalObject(source *simplejson.Json) interface{} {
result := make(map[string]interface{})
for key, value := range source.MustMap() {
if key == "__inputs" {
continue
}
result[key] = e.evalValue(simplejson.NewFromAny(value))
}
return result
}