dashboard_importer.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. package plugins
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "regexp"
  6. "github.com/grafana/grafana/pkg/bus"
  7. "github.com/grafana/grafana/pkg/components/simplejson"
  8. m "github.com/grafana/grafana/pkg/models"
  9. )
  10. type ImportDashboardCommand struct {
  11. Path string `json:"string"`
  12. Inputs []ImportDashboardInput `json:"inputs"`
  13. OrgId int64 `json:"-"`
  14. UserId int64 `json:"-"`
  15. PluginId string `json:"-"`
  16. Result *PluginDashboardInfoDTO
  17. }
  18. type ImportDashboardInput struct {
  19. Type string `json:"type"`
  20. PluginId string `json:"pluginId"`
  21. Name string `json:"name"`
  22. Value string `json:"value"`
  23. }
  24. type DashboardInputMissingError struct {
  25. VariableName string
  26. }
  27. func (e DashboardInputMissingError) Error() string {
  28. return fmt.Sprintf("Dashbord input variable: %v missing from import command", e.VariableName)
  29. }
  30. func init() {
  31. bus.AddHandler("plugins", ImportDashboard)
  32. }
  33. func ImportDashboard(cmd *ImportDashboardCommand) error {
  34. plugin, exists := Plugins[cmd.PluginId]
  35. if !exists {
  36. return PluginNotFoundError{cmd.PluginId}
  37. }
  38. var dashboard *m.Dashboard
  39. var err error
  40. if dashboard, err = loadPluginDashboard(plugin, cmd.Path); err != nil {
  41. return err
  42. }
  43. evaluator := &DashTemplateEvaluator{
  44. template: dashboard.Data,
  45. inputs: cmd.Inputs,
  46. }
  47. generatedDash, err := evaluator.Eval()
  48. if err != nil {
  49. return err
  50. }
  51. saveCmd := m.SaveDashboardCommand{
  52. Dashboard: generatedDash,
  53. OrgId: cmd.OrgId,
  54. UserId: cmd.UserId,
  55. }
  56. if err := bus.Dispatch(&saveCmd); err != nil {
  57. return err
  58. }
  59. cmd.Result = &PluginDashboardInfoDTO{
  60. PluginId: cmd.PluginId,
  61. Title: dashboard.Title,
  62. Path: cmd.Path,
  63. Revision: dashboard.GetString("revision", "1.0"),
  64. InstalledUri: "db/" + saveCmd.Result.Slug,
  65. InstalledRevision: dashboard.GetString("revision", "1.0"),
  66. Installed: true,
  67. }
  68. return nil
  69. }
  70. type DashTemplateEvaluator struct {
  71. template *simplejson.Json
  72. inputs []ImportDashboardInput
  73. variables map[string]string
  74. result *simplejson.Json
  75. varRegex *regexp.Regexp
  76. }
  77. func (this *DashTemplateEvaluator) findInput(varName string, varType string) *ImportDashboardInput {
  78. for _, input := range this.inputs {
  79. if varType == input.Type && (input.Name == varName || input.Name == "*") {
  80. return &input
  81. }
  82. }
  83. return nil
  84. }
  85. func (this *DashTemplateEvaluator) Eval() (*simplejson.Json, error) {
  86. this.result = simplejson.New()
  87. this.variables = make(map[string]string)
  88. this.varRegex, _ = regexp.Compile(`(\$\{\w+\})`)
  89. // check that we have all inputs we need
  90. for _, inputDef := range this.template.Get("__inputs").MustArray() {
  91. inputDefJson := simplejson.NewFromAny(inputDef)
  92. inputName := inputDefJson.Get("name").MustString()
  93. inputType := inputDefJson.Get("type").MustString()
  94. input := this.findInput(inputName, inputType)
  95. if input == nil {
  96. return nil, &DashboardInputMissingError{VariableName: inputName}
  97. }
  98. this.variables["${"+inputName+"}"] = input.Value
  99. }
  100. return simplejson.NewFromAny(this.evalObject(this.template)), nil
  101. }
  102. func (this *DashTemplateEvaluator) evalValue(source *simplejson.Json) interface{} {
  103. sourceValue := source.Interface()
  104. switch v := sourceValue.(type) {
  105. case string:
  106. interpolated := this.varRegex.ReplaceAllStringFunc(v, func(match string) string {
  107. if replacement, exists := this.variables[match]; exists {
  108. return replacement
  109. } else {
  110. return match
  111. }
  112. })
  113. return interpolated
  114. case bool:
  115. return v
  116. case json.Number:
  117. return v
  118. case map[string]interface{}:
  119. return this.evalObject(source)
  120. case []interface{}:
  121. array := make([]interface{}, 0)
  122. for _, item := range v {
  123. array = append(array, this.evalValue(simplejson.NewFromAny(item)))
  124. }
  125. return array
  126. }
  127. return nil
  128. }
  129. func (this *DashTemplateEvaluator) evalObject(source *simplejson.Json) interface{} {
  130. result := make(map[string]interface{})
  131. for key, value := range source.MustMap() {
  132. if key == "__inputs" {
  133. continue
  134. }
  135. result[key] = this.evalValue(simplejson.NewFromAny(value))
  136. }
  137. return result
  138. }