grafana/pkg/plugins/dashboard_importer.go

174 lines
4.0 KiB
Go
Raw Normal View History

package plugins
import (
"encoding/json"
2016-03-12 06:28:33 +08:00
"fmt"
"regexp"
"github.com/grafana/grafana/pkg/bus"
2016-03-12 07:13:06 +08:00
"github.com/grafana/grafana/pkg/components/simplejson"
m "github.com/grafana/grafana/pkg/models"
)
type ImportDashboardCommand struct {
2016-05-14 16:00:43 +08:00
Dashboard *simplejson.Json
Path string
Inputs []ImportDashboardInput
Overwrite bool
OrgId int64
UserId int64
PluginId string
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)
}
func init() {
bus.AddHandler("plugins", ImportDashboard)
}
func ImportDashboard(cmd *ImportDashboardCommand) error {
var dashboard *m.Dashboard
var err error
2016-05-14 16:00:43 +08:00
if cmd.PluginId != "" {
if dashboard, err = loadPluginDashboard(cmd.PluginId, cmd.Path); err != nil {
return err
}
} else {
dashboard = m.NewDashboardFromJson(cmd.Dashboard)
}
2016-03-12 06:28:33 +08:00
evaluator := &DashTemplateEvaluator{
2016-03-12 07:13:06 +08:00
template: dashboard.Data,
2016-03-12 06:28:33 +08:00
inputs: cmd.Inputs,
}
generatedDash, err := evaluator.Eval()
if err != nil {
return err
}
saveCmd := m.SaveDashboardCommand{
2016-03-12 07:13:06 +08:00
Dashboard: generatedDash,
OrgId: cmd.OrgId,
UserId: cmd.UserId,
Overwrite: cmd.Overwrite,
}
if err := bus.Dispatch(&saveCmd); err != nil {
return err
}
cmd.Result = &PluginDashboardInfoDTO{
2016-05-14 16:00:43 +08:00
PluginId: cmd.PluginId,
Title: dashboard.Title,
Path: cmd.Path,
Revision: dashboard.Data.Get("revision").MustInt64(1),
ImportedUri: "db/" + saveCmd.Result.Slug,
ImportedRevision: dashboard.Data.Get("revision").MustInt64(1),
Imported: true,
}
return nil
}
type DashTemplateEvaluator struct {
2016-03-12 07:13:06 +08:00
template *simplejson.Json
inputs []ImportDashboardInput
variables map[string]string
2016-03-12 07:13:06 +08:00
result *simplejson.Json
2016-03-12 06:28:33 +08:00
varRegex *regexp.Regexp
}
func (this *DashTemplateEvaluator) findInput(varName string, varType string) *ImportDashboardInput {
for _, input := range this.inputs {
if varType == input.Type && (input.Name == varName || input.Name == "*") {
return &input
}
}
return nil
}
2016-03-12 07:13:06 +08:00
func (this *DashTemplateEvaluator) Eval() (*simplejson.Json, error) {
this.result = simplejson.New()
this.variables = make(map[string]string)
this.varRegex, _ = regexp.Compile(`(\$\{\w+\})`)
// check that we have all inputs we need
for _, inputDef := range this.template.Get("__inputs").MustArray() {
inputDefJson := simplejson.NewFromAny(inputDef)
inputName := inputDefJson.Get("name").MustString()
inputType := inputDefJson.Get("type").MustString()
input := this.findInput(inputName, inputType)
if input == nil {
return nil, &DashboardInputMissingError{VariableName: inputName}
}
this.variables["${"+inputName+"}"] = input.Value
}
return simplejson.NewFromAny(this.evalObject(this.template)), nil
}
func (this *DashTemplateEvaluator) evalValue(source *simplejson.Json) interface{} {
sourceValue := source.Interface()
switch v := sourceValue.(type) {
case string:
interpolated := this.varRegex.ReplaceAllStringFunc(v, func(match string) string {
if replacement, exists := this.variables[match]; exists {
return replacement
} else {
return match
}
})
return interpolated
case bool:
return v
case json.Number:
return v
case map[string]interface{}:
return this.evalObject(source)
case []interface{}:
array := make([]interface{}, 0)
for _, item := range v {
array = append(array, this.evalValue(simplejson.NewFromAny(item)))
}
return array
}
return nil
}
func (this *DashTemplateEvaluator) evalObject(source *simplejson.Json) interface{} {
result := make(map[string]interface{})
2016-03-12 07:13:06 +08:00
for key, value := range source.MustMap() {
2016-03-12 06:28:33 +08:00
if key == "__inputs" {
continue
}
result[key] = this.evalValue(simplejson.NewFromAny(value))
}
return result
}