rendering.go 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package rendering
  2. import (
  3. "context"
  4. "fmt"
  5. "net/url"
  6. "os"
  7. "path/filepath"
  8. plugin "github.com/hashicorp/go-plugin"
  9. pluginModel "github.com/grafana/grafana-plugin-model/go/renderer"
  10. "github.com/grafana/grafana/pkg/log"
  11. "github.com/grafana/grafana/pkg/middleware"
  12. "github.com/grafana/grafana/pkg/models"
  13. "github.com/grafana/grafana/pkg/plugins"
  14. "github.com/grafana/grafana/pkg/registry"
  15. "github.com/grafana/grafana/pkg/setting"
  16. "github.com/grafana/grafana/pkg/util"
  17. )
  18. func init() {
  19. registry.RegisterService(&RenderingService{})
  20. }
  21. type RenderingService struct {
  22. log log.Logger
  23. pluginClient *plugin.Client
  24. grpcPlugin pluginModel.RendererPlugin
  25. pluginInfo *plugins.RendererPlugin
  26. renderAction renderFunc
  27. domain string
  28. Cfg *setting.Cfg `inject:""`
  29. }
  30. func (rs *RenderingService) Init() error {
  31. rs.log = log.New("rendering")
  32. // ensure ImagesDir exists
  33. err := os.MkdirAll(rs.Cfg.ImagesDir, 0700)
  34. if err != nil {
  35. return err
  36. }
  37. // set value used for domain attribute of renderKey cookie
  38. if rs.Cfg.RendererUrl != "" {
  39. // RendererCallbackUrl has already been passed, it won't generate an error.
  40. u, _ := url.Parse(rs.Cfg.RendererCallbackUrl)
  41. rs.domain = u.Hostname()
  42. } else if setting.HttpAddr != setting.DEFAULT_HTTP_ADDR {
  43. rs.domain = setting.HttpAddr
  44. } else {
  45. rs.domain = "localhost"
  46. }
  47. return nil
  48. }
  49. func (rs *RenderingService) Run(ctx context.Context) error {
  50. if rs.Cfg.RendererUrl != "" {
  51. rs.log.Info("Backend rendering via external http server")
  52. rs.renderAction = rs.renderViaHttp
  53. <-ctx.Done()
  54. return nil
  55. }
  56. if plugins.Renderer == nil {
  57. rs.renderAction = rs.renderViaPhantomJS
  58. <-ctx.Done()
  59. return nil
  60. }
  61. rs.pluginInfo = plugins.Renderer
  62. if err := rs.startPlugin(ctx); err != nil {
  63. return err
  64. }
  65. rs.renderAction = rs.renderViaPlugin
  66. err := rs.watchAndRestartPlugin(ctx)
  67. if rs.pluginClient != nil {
  68. rs.log.Debug("Killing renderer plugin process")
  69. rs.pluginClient.Kill()
  70. }
  71. return err
  72. }
  73. func (rs *RenderingService) Render(ctx context.Context, opts Opts) (*RenderResult, error) {
  74. if rs.renderAction != nil {
  75. return rs.renderAction(ctx, opts)
  76. } else {
  77. return nil, fmt.Errorf("No renderer found")
  78. }
  79. }
  80. func (rs *RenderingService) getFilePathForNewImage() string {
  81. pngPath, _ := filepath.Abs(filepath.Join(rs.Cfg.ImagesDir, util.GetRandomString(20)))
  82. return pngPath + ".png"
  83. }
  84. func (rs *RenderingService) getURL(path string) string {
  85. if rs.Cfg.RendererUrl != "" {
  86. // The backend rendering service can potentially be remote.
  87. // So we need to use the root_url to ensure the rendering service
  88. // can reach this Grafana instance.
  89. // &render=1 signals to the legacy redirect layer to
  90. return fmt.Sprintf("%s%s&render=1", rs.Cfg.RendererCallbackUrl, path)
  91. }
  92. // &render=1 signals to the legacy redirect layer to
  93. return fmt.Sprintf("%s://%s:%s/%s&render=1", setting.Protocol, rs.domain, setting.HttpPort, path)
  94. }
  95. func (rs *RenderingService) getRenderKey(orgId, userId int64, orgRole models.RoleType) string {
  96. return middleware.AddRenderAuthKey(orgId, userId, orgRole)
  97. }