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