dashboard_importer.go 4.3 KB

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