Image Rendering: Remove PhantomJS support (#23460)
Removes all references and usage of PhantomJS #23375. Remove direct link rendered image e2e smoke test for now. Docker: Fix installing chrome in ubuntu custom docker image. Improve handling of image renderer not available/installed #23593. Add PhantomJS breaking change and upgrading notes. Use grabpl v0.2.10. Closes #13802 Co-authored-by: Kyle Brandt <kyle@grafana.com> Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com> Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>
This commit is contained in:
co-authored by
Kyle Brandt
Arve Knudsen
Diana Payton
parent
0a1ab60b8c
commit
6e313e7d37
@@ -32,6 +32,7 @@ type RenderResult struct {
|
||||
type renderFunc func(ctx context.Context, renderKey string, options Opts) (*RenderResult, error)
|
||||
|
||||
type Service interface {
|
||||
IsAvailable() bool
|
||||
Render(ctx context.Context, opts Opts) (*RenderResult, error)
|
||||
RenderErrorImage(error error) (*RenderResult, error)
|
||||
GetRenderUser(key string) (*RenderUser, bool)
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
package rendering
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log"
|
||||
)
|
||||
|
||||
func (rs *RenderingService) renderViaPhantomJS(ctx context.Context, renderKey string, opts Opts) (*RenderResult, error) {
|
||||
var executable = "phantomjs"
|
||||
if runtime.GOOS == "windows" {
|
||||
executable = executable + ".exe"
|
||||
}
|
||||
|
||||
url := rs.getURL(opts.Path)
|
||||
binPath, _ := filepath.Abs(filepath.Join(rs.Cfg.PhantomDir, executable))
|
||||
if _, err := os.Stat(binPath); os.IsNotExist(err) {
|
||||
rs.log.Error("executable not found", "executable", binPath)
|
||||
return nil, ErrPhantomJSNotInstalled
|
||||
}
|
||||
|
||||
scriptPath, _ := filepath.Abs(filepath.Join(rs.Cfg.PhantomDir, "render.js"))
|
||||
pngPath, err := rs.getFilePathForNewImage()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
phantomDebugArg := "--debug=false"
|
||||
if log.GetLogLevelFor("rendering") >= log.LvlDebug {
|
||||
phantomDebugArg = "--debug=true"
|
||||
}
|
||||
|
||||
cmdArgs := []string{
|
||||
"--ignore-ssl-errors=true",
|
||||
"--web-security=true",
|
||||
"--local-url-access=false",
|
||||
phantomDebugArg,
|
||||
scriptPath,
|
||||
fmt.Sprintf("url=%v", url),
|
||||
fmt.Sprintf("width=%v", opts.Width),
|
||||
fmt.Sprintf("height=%v", opts.Height),
|
||||
fmt.Sprintf("png=%v", pngPath),
|
||||
fmt.Sprintf("domain=%v", rs.domain),
|
||||
fmt.Sprintf("timeout=%v", opts.Timeout.Seconds()),
|
||||
fmt.Sprintf("renderKey=%v", renderKey),
|
||||
}
|
||||
|
||||
if opts.Encoding != "" {
|
||||
cmdArgs = append([]string{fmt.Sprintf("--output-encoding=%s", opts.Encoding)}, cmdArgs...)
|
||||
}
|
||||
|
||||
// gives phantomjs some additional time to timeout and return possible errors.
|
||||
commandCtx, cancel := context.WithTimeout(ctx, opts.Timeout+time.Second*2)
|
||||
defer cancel()
|
||||
|
||||
cmd := exec.CommandContext(commandCtx, binPath, cmdArgs...)
|
||||
cmd.Stderr = cmd.Stdout
|
||||
|
||||
timezone := ""
|
||||
|
||||
cmd.Env = os.Environ()
|
||||
|
||||
if opts.Timezone != "" {
|
||||
timezone = isoTimeOffsetToPosixTz(opts.Timezone)
|
||||
cmd.Env = appendEnviron(cmd.Env, "TZ", timezone)
|
||||
}
|
||||
|
||||
// Added to disable usage of newer version of OPENSSL
|
||||
// that seem to be incompatible with PhantomJS (used in Debian Buster)
|
||||
if runtime.GOOS == "linux" {
|
||||
disableNewOpenssl := "/etc/ssl"
|
||||
cmd.Env = appendEnviron(cmd.Env, "OPENSSL_CONF", disableNewOpenssl)
|
||||
}
|
||||
|
||||
rs.log.Debug("executing Phantomjs", "binPath", binPath, "cmdArgs", cmdArgs, "timezone", timezone)
|
||||
|
||||
out, err := cmd.Output()
|
||||
|
||||
if out != nil {
|
||||
rs.log.Debug("Phantomjs output", "out", string(out))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
rs.log.Debug("Phantomjs error", "error", err)
|
||||
}
|
||||
|
||||
// check for timeout first
|
||||
if commandCtx.Err() == context.DeadlineExceeded {
|
||||
rs.log.Info("Rendering timed out")
|
||||
return nil, ErrTimeout
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
rs.log.Error("Phantomjs exited with non zero exit code", "error", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rs.log.Debug("Image rendered", "path", pngPath)
|
||||
return &RenderResult{FilePath: pngPath}, nil
|
||||
}
|
||||
|
||||
func isoTimeOffsetToPosixTz(isoOffset string) string {
|
||||
// invert offset
|
||||
if strings.HasPrefix(isoOffset, "UTC+") {
|
||||
return strings.Replace(isoOffset, "UTC+", "UTC-", 1)
|
||||
}
|
||||
if strings.HasPrefix(isoOffset, "UTC-") {
|
||||
return strings.Replace(isoOffset, "UTC-", "UTC+", 1)
|
||||
}
|
||||
return isoOffset
|
||||
}
|
||||
|
||||
func appendEnviron(baseEnviron []string, name string, value string) []string {
|
||||
results := make([]string, 0)
|
||||
prefix := fmt.Sprintf("%s=", name)
|
||||
for _, v := range baseEnviron {
|
||||
if !strings.HasPrefix(v, prefix) {
|
||||
results = append(results, v)
|
||||
}
|
||||
}
|
||||
return append(results, fmt.Sprintf("%s=%s", name, value))
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/infra/remotecache"
|
||||
@@ -23,8 +24,6 @@ func init() {
|
||||
registry.RegisterService(&RenderingService{})
|
||||
}
|
||||
|
||||
var IsPhantomJSEnabled = false
|
||||
|
||||
const renderKeyPrefix = "render-%s"
|
||||
|
||||
type RenderUser struct {
|
||||
@@ -76,30 +75,31 @@ func (rs *RenderingService) Run(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
if plugins.Renderer == nil {
|
||||
rs.log = rs.log.New("renderer", "phantomJS")
|
||||
rs.log.Info("Backend rendering via phantomJS")
|
||||
rs.log.Warn("phantomJS is deprecated and will be removed in a future release. " +
|
||||
"You should consider migrating from phantomJS to grafana-image-renderer plugin. " +
|
||||
"Read more at https://grafana.com/docs/grafana/latest/administration/image_rendering/")
|
||||
rs.renderAction = rs.renderViaPhantomJS
|
||||
IsPhantomJSEnabled = true
|
||||
if plugins.Renderer != nil {
|
||||
rs.log = rs.log.New("renderer", "plugin")
|
||||
rs.pluginInfo = plugins.Renderer
|
||||
|
||||
if err := rs.startPlugin(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rs.renderAction = rs.renderViaPlugin
|
||||
<-ctx.Done()
|
||||
return nil
|
||||
}
|
||||
|
||||
rs.log = rs.log.New("renderer", "plugin")
|
||||
rs.pluginInfo = plugins.Renderer
|
||||
rs.log.Debug("No image renderer found/installed. " +
|
||||
"For image rendering support please install the grafana-image-renderer plugin. " +
|
||||
"Read more at https://grafana.com/docs/grafana/latest/administration/image_rendering/")
|
||||
|
||||
if err := rs.startPlugin(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rs.renderAction = rs.renderViaPlugin
|
||||
<-ctx.Done()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rs *RenderingService) IsAvailable() bool {
|
||||
return rs.renderAction != nil
|
||||
}
|
||||
|
||||
func (rs *RenderingService) RenderErrorImage(err error) (*RenderResult, error) {
|
||||
imgUrl := "public/img/rendering_error.png"
|
||||
|
||||
@@ -209,3 +209,14 @@ func (rs *RenderingService) deleteRenderKey(key string) {
|
||||
rs.log.Error("Failed to delete render key", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func isoTimeOffsetToPosixTz(isoOffset string) string {
|
||||
// invert offset
|
||||
if strings.HasPrefix(isoOffset, "UTC+") {
|
||||
return strings.Replace(isoOffset, "UTC+", "UTC-", 1)
|
||||
}
|
||||
if strings.HasPrefix(isoOffset, "UTC-") {
|
||||
return strings.Replace(isoOffset, "UTC-", "UTC+", 1)
|
||||
}
|
||||
return isoOffset
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user