dashboard_importer.go 3.9 KB

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