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