mirror of https://github.com/grafana/grafana
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>pull/23602/head
parent
0a1ab60b8c
commit
6e313e7d37
Before Width: | Height: | Size: 26 KiB |
@ -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)) |
||||
} |
@ -1,24 +0,0 @@ |
||||
#!/bin/bash |
||||
set -eo pipefail |
||||
|
||||
if [ ! -d '/tmp/phantomjs' ]; then |
||||
_version="2.1.1" |
||||
|
||||
curl -fL https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-$_version-windows.zip -o /tmp/phantomjs-win.zip |
||||
[ "$(sha256sum /tmp/phantomjs-win.zip | cut -d' ' -f1)" = \ |
||||
"d9fb05623d6b26d3654d008eab3adafd1f6350433dfd16138c46161f42c7dcc8" ] || \ |
||||
(echo "Checksum mismatch phantomjs-$_version-windows.zip"; exit 1) |
||||
curl -fL https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-$_version-macosx.zip -o /tmp/phantomjs-mac.zip |
||||
[ "$(sha256sum /tmp/phantomjs-mac.zip | cut -d' ' -f1)" = \ |
||||
"538cf488219ab27e309eafc629e2bcee9976990fe90b1ec334f541779150f8c1" ] || \ |
||||
(echo "Checksum mismatch phantomjs-$_version-mac.zip"; exit 1) |
||||
|
||||
cd /tmp |
||||
unzip /tmp/phantomjs-win.zip |
||||
unzip /tmp/phantomjs-mac.zip |
||||
|
||||
mkdir -p /tmp/phantomjs/windows /tmp/phantomjs/darwin |
||||
|
||||
cp /tmp/phantomjs-$_version-windows/bin/phantomjs.exe /tmp/phantomjs/windows/phantomjs.exe |
||||
cp /tmp/phantomjs-$_version-macosx/bin/phantomjs /tmp/phantomjs/darwin/phantomjs |
||||
fi |
@ -1,33 +0,0 @@ |
||||
module.exports = function(config,grunt) { |
||||
'use strict'; |
||||
|
||||
grunt.registerTask('phantomjs', 'Copy phantomjs binary to vendor/', function() { |
||||
var dest = './tools/phantomjs/phantomjs'; |
||||
var confDir = './node_modules/phantomjs-prebuilt/lib/'; |
||||
|
||||
if (process.platform === "win32") { |
||||
dest += ".exe"; |
||||
} |
||||
|
||||
var src = config.phjs; |
||||
if (!src) { |
||||
var m = grunt.file.read(confDir+"location.js"); |
||||
src = /= \"([^\"]*)\"/.exec(m)[1]; |
||||
if (!grunt.file.isPathAbsolute(src)) { |
||||
src = confDir+src; |
||||
} |
||||
} |
||||
|
||||
try { |
||||
grunt.config('copy.phantom_bin', { |
||||
src: src, |
||||
dest: dest, |
||||
options: { mode: true}, |
||||
}); |
||||
grunt.task.run('copy:phantom_bin'); |
||||
} catch (err) { |
||||
grunt.verbose.writeln(err); |
||||
grunt.fail.warn('No working Phantomjs binary available') |
||||
} |
||||
}); |
||||
}; |
@ -1,86 +0,0 @@ |
||||
(function() { |
||||
'use strict'; |
||||
|
||||
var page = require('webpage').create(); |
||||
var args = require('system').args; |
||||
var params = {}; |
||||
var regexp = /^([^=]+)=([^$]+)/; |
||||
|
||||
args.forEach(function(arg) { |
||||
var parts = arg.match(regexp); |
||||
if (!parts) { |
||||
return; |
||||
} |
||||
params[parts[1]] = parts[2]; |
||||
}); |
||||
|
||||
var usage = 'url=<url> png=<filename> width=<width> height=<height> renderKey=<key>'; |
||||
|
||||
if (!params.url || !params.png || !params.renderKey || !params.domain) { |
||||
console.log(usage); |
||||
phantom.exit(); |
||||
} |
||||
|
||||
phantom.addCookie({ |
||||
name: 'renderKey', |
||||
value: params.renderKey, |
||||
domain: params.domain, |
||||
}); |
||||
|
||||
page.viewportSize = { |
||||
width: params.width || '800', |
||||
height: params.height || '400', |
||||
}; |
||||
|
||||
var timeoutMs = (parseInt(params.timeout) || 10) * 1000; |
||||
var waitBetweenReadyCheckMs = 50; |
||||
var totalWaitMs = 0; |
||||
|
||||
page.open(params.url, function(status) { |
||||
console.log('Loading a web page: ' + params.url + ' status: ' + status, timeoutMs); |
||||
|
||||
page.onError = function(msg, trace) { |
||||
var msgStack = ['ERROR: ' + msg]; |
||||
if (trace && trace.length) { |
||||
msgStack.push('TRACE:'); |
||||
trace.forEach(function(t) { |
||||
msgStack.push(' -> ' + t.file + ': ' + t.line + (t.function ? ' (in function "' + t.function + '")' : '')); |
||||
}); |
||||
} |
||||
console.error(msgStack.join('\n')); |
||||
}; |
||||
|
||||
function checkIsReady() { |
||||
var panelsRendered = page.evaluate(function() { |
||||
var panelCount = document.querySelectorAll('plugin-component').length; |
||||
return window.panelsRendered >= panelCount; |
||||
}); |
||||
|
||||
if (panelsRendered || totalWaitMs > timeoutMs) { |
||||
var bb = page.evaluate(function() { |
||||
var container = document.getElementsByClassName('dashboard-container'); |
||||
if (container.length == 0) { |
||||
container = document.getElementsByClassName('panel-container'); |
||||
} |
||||
return container[0].getBoundingClientRect(); |
||||
}); |
||||
|
||||
// reset viewport to render full page
|
||||
page.viewportSize = { |
||||
width: bb.width, |
||||
height: bb.height, |
||||
}; |
||||
|
||||
setTimeout(function() { |
||||
page.render(params.png); |
||||
phantom.exit(); |
||||
}, 5); |
||||
} else { |
||||
totalWaitMs += waitBetweenReadyCheckMs; |
||||
setTimeout(checkIsReady, waitBetweenReadyCheckMs); |
||||
} |
||||
} |
||||
|
||||
setTimeout(checkIsReady, waitBetweenReadyCheckMs); |
||||
}); |
||||
})(); |
Loading…
Reference in new issue