dashboard_importer.go 4.4 KB

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