2016-03-12 00:31:57 +08:00
|
|
|
package plugins
|
|
|
|
|
|
|
|
|
|
import (
|
2016-03-12 06:28:33 +08:00
|
|
|
"fmt"
|
|
|
|
|
"reflect"
|
|
|
|
|
"regexp"
|
|
|
|
|
|
2016-03-12 00:31:57 +08:00
|
|
|
"github.com/grafana/grafana/pkg/bus"
|
|
|
|
|
"github.com/grafana/grafana/pkg/components/dynmap"
|
|
|
|
|
"github.com/grafana/grafana/pkg/log"
|
|
|
|
|
m "github.com/grafana/grafana/pkg/models"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type ImportDashboardCommand struct {
|
|
|
|
|
Path string `json:"string"`
|
|
|
|
|
Inputs []ImportDashboardInput `json:"inputs"`
|
|
|
|
|
|
|
|
|
|
OrgId int64 `json:"-"`
|
|
|
|
|
UserId int64 `json:"-"`
|
|
|
|
|
PluginId string `json:"-"`
|
|
|
|
|
Result *PluginDashboardInfoDTO
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type ImportDashboardInput struct {
|
|
|
|
|
Type string `json:"type"`
|
|
|
|
|
PluginId string `json:"pluginId"`
|
|
|
|
|
Name string `json:"name"`
|
|
|
|
|
Value string `json:"value"`
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-12 06:28:33 +08:00
|
|
|
type DashboardInputMissingError struct {
|
|
|
|
|
VariableName string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (e DashboardInputMissingError) Error() string {
|
|
|
|
|
return fmt.Sprintf("Dashbord input variable: %v missing from import command", e.VariableName)
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-12 00:31:57 +08:00
|
|
|
func init() {
|
|
|
|
|
bus.AddHandler("plugins", ImportDashboard)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func ImportDashboard(cmd *ImportDashboardCommand) error {
|
|
|
|
|
plugin, exists := Plugins[cmd.PluginId]
|
|
|
|
|
|
|
|
|
|
if !exists {
|
|
|
|
|
return PluginNotFoundError{cmd.PluginId}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var dashboard *m.Dashboard
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
if dashboard, err = loadPluginDashboard(plugin, cmd.Path); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-12 06:28:33 +08:00
|
|
|
template := dynmap.NewFromMap(dashboard.Data)
|
|
|
|
|
evaluator := &DashTemplateEvaluator{
|
|
|
|
|
template: template,
|
|
|
|
|
inputs: cmd.Inputs,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
generatedDash, err := evaluator.Eval()
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
2016-03-12 00:31:57 +08:00
|
|
|
saveCmd := m.SaveDashboardCommand{
|
2016-03-12 06:28:33 +08:00
|
|
|
Dashboard: generatedDash.StringMap(),
|
2016-03-12 00:31:57 +08:00
|
|
|
OrgId: cmd.OrgId,
|
|
|
|
|
UserId: cmd.UserId,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err := bus.Dispatch(&saveCmd); err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmd.Result = &PluginDashboardInfoDTO{
|
|
|
|
|
PluginId: cmd.PluginId,
|
|
|
|
|
Title: dashboard.Title,
|
|
|
|
|
Path: cmd.Path,
|
|
|
|
|
Revision: dashboard.GetString("revision", "1.0"),
|
|
|
|
|
InstalledUri: "db/" + saveCmd.Result.Slug,
|
|
|
|
|
InstalledRevision: dashboard.GetString("revision", "1.0"),
|
|
|
|
|
Installed: true,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type DashTemplateEvaluator struct {
|
|
|
|
|
template *dynmap.Object
|
|
|
|
|
inputs []ImportDashboardInput
|
|
|
|
|
variables map[string]string
|
|
|
|
|
result *dynmap.Object
|
2016-03-12 06:28:33 +08:00
|
|
|
varRegex *regexp.Regexp
|
2016-03-12 00:31:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (this *DashTemplateEvaluator) findInput(varName string, varDef *dynmap.Object) *ImportDashboardInput {
|
|
|
|
|
inputType, _ := varDef.GetString("type")
|
|
|
|
|
|
|
|
|
|
for _, input := range this.inputs {
|
|
|
|
|
if inputType == input.Type && (input.Name == varName || input.Name == "*") {
|
|
|
|
|
return &input
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (this *DashTemplateEvaluator) Eval() (*dynmap.Object, error) {
|
|
|
|
|
this.result = dynmap.NewObject()
|
|
|
|
|
this.variables = make(map[string]string)
|
2016-03-12 06:28:33 +08:00
|
|
|
this.varRegex, _ = regexp.Compile("\\$__(\\w+)")
|
2016-03-12 00:31:57 +08:00
|
|
|
|
|
|
|
|
// check that we have all inputs we need
|
|
|
|
|
if requiredInputs, err := this.template.GetObject("__inputs"); err == nil {
|
|
|
|
|
for varName, value := range requiredInputs.Map() {
|
|
|
|
|
varDef, _ := value.Object()
|
|
|
|
|
input := this.findInput(varName, varDef)
|
2016-03-12 06:28:33 +08:00
|
|
|
|
|
|
|
|
if input == nil {
|
|
|
|
|
return nil, &DashboardInputMissingError{VariableName: varName}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.variables["$__"+varName] = input.Value
|
2016-03-12 00:31:57 +08:00
|
|
|
}
|
2016-03-12 06:28:33 +08:00
|
|
|
} else {
|
|
|
|
|
log.Info("Import: dashboard has no __import section")
|
2016-03-12 00:31:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this.EvalObject(this.template, this.result)
|
|
|
|
|
return this.result, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (this *DashTemplateEvaluator) EvalObject(source *dynmap.Object, writer *dynmap.Object) {
|
|
|
|
|
|
|
|
|
|
for key, value := range source.Map() {
|
2016-03-12 06:28:33 +08:00
|
|
|
if key == "__inputs" {
|
2016-03-12 00:31:57 +08:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
goValue := value.Interface()
|
2016-03-12 06:28:33 +08:00
|
|
|
|
|
|
|
|
switch v := goValue.(type) {
|
2016-03-12 00:31:57 +08:00
|
|
|
case string:
|
2016-03-12 06:28:33 +08:00
|
|
|
interpolated := this.varRegex.ReplaceAllStringFunc(v, func(match string) string {
|
|
|
|
|
return this.variables[match]
|
|
|
|
|
})
|
|
|
|
|
writer.SetValue(key, interpolated)
|
2016-03-12 00:31:57 +08:00
|
|
|
case map[string]interface{}:
|
|
|
|
|
childSource, _ := value.Object()
|
|
|
|
|
childWriter, _ := writer.SetValue(key, map[string]interface{}{}).Object()
|
|
|
|
|
this.EvalObject(childSource, childWriter)
|
|
|
|
|
default:
|
2016-03-12 06:28:33 +08:00
|
|
|
log.Info("type: %v", reflect.TypeOf(goValue))
|
2016-03-12 00:31:57 +08:00
|
|
|
log.Error(3, "Unknown json type key: %v , type: %v", key, goValue)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|