Implement Webdriver - #88
Conversation
cf3eb8d to
1a6156a
Compare
|
If you use docker you can just use the two services provided in the PR description. To test the legacy chrome backend, just follow the existing documentation. The PdfExport module allows you to create PDFs of any page in IW2, it is also used to create reports with a custom cover page in the reporting module. |
It is not. The connection to the user can time out before the PDF is done generating, that seems to be a problem that has always existed, and this PR doesn't change that. |
|
Please have a look at this comment and the screenshot. |
This has been addressed in 6861696 |
| 'required' => true, | ||
| 'placeholder' => 100, | ||
| 'min' => 0, | ||
| 'description' => $this->translate('The priority of the backend. A lower priority will be used first.'), |
There was a problem hiding this comment.
This ordering seems counter-intuitive to me at first sight.
@flourish86 What do you think?
There was a problem hiding this comment.
This is the same order as menu items internally.
To be fair afaik. it is the first time that a user would have to interact with the number directly.
| $this->addContent($table); | ||
| } | ||
|
|
||
| public function backendAction(): void |
There was a problem hiding this comment.
Being able to rename a backend would be nice. See Icinga/icinga-sso-web#3
There was a problem hiding this comment.
Shouldn't be necessary if you use random IDs as section keys like Icinga/icinga-sso-web#3.
There was a problem hiding this comment.
I don't think randomize IDs are necessary here. They make the config file hard to read and probably cause problems with configuration management. The INI section name is usually the name if the resource, so I implemented this exact behaviour in Icinga/icingaweb2#5480 Icinga/icingaweb2#5567.
| $this->addContent($table); | ||
| } | ||
|
|
||
| public function backendAction(): void |
There was a problem hiding this comment.
Being able to deactivate a backend temporarily for testing would be nice, but I guess changing priorities will do it as well. You decide.
3fd2c34 to
d19553a
Compare
On some distributions (e.g. Fedora), `/usr/bin/chromium-browser` is a shell wrapper that adds `--enable-sync` to Chrome's flags and reroutes stderr through a buffering subprocess: ```bash exec 2> >(exec cat >&2) ``` This creates a double-pipe between Chrome and PHP with a combined buffer of ~128 KB. `--enable-sync` causes Chrome to emit verbose startup logging that fills this buffer. Chrome's IO thread handles both stderr writes and the DevTools HTTP server, so once the buffer is full the entire DevTools protocol stalls -- `getJsonVersion()` would hang for up to 60 seconds until Chrome finished writing. Fix: after the DevTools socket is found, drain the stderr pipe in a loop while probing the HTTP endpoint with short timeouts. Once Chrome responds, close the read end of the pipe. Chrome ignores SIGPIPE, so subsequent stderr writes fail silently without blocking. To support this, ShellCommand gains three methods: `getStderrPipe()` to expose the pipe resource for external draining, `getStderr()` to retrieve accumulated output after `wait()` returns (used for startup failure diagnostics), and `closeStderrPipe()` to close the pipe without stopping the process. `stop()` is guarded against double-close in case `closeStderrPipe()` was called first.
Google Chrome and Fedora's chromium-browser both route Chrome's stderr through a process substitution `(exec 2> >(exec cat >&2))`. This caused two failures: - Fedora: cat filled the pipe buffer, blocking Chrome's IO thread - Ubuntu Chrome 152: closing PHP's read end sent SIGPIPE to cat, making Chrome's FD2 return EPIPE Fix: append `2>/dev/null` to the Linux command line so cat's output goes to `/dev/null`, preventing both blocking and EPIPE. Since stderr is now discarded, switch from stderr regex parsing to polling Chrome's DevToolsActivePort file for the DevTools port and browser ID.
IcingaWeb2 passes a null title when the view has no title set. `setTitle()` and `getTitle()` now accept and return `?string.`
Ubuntu 26.04's apache2 systemd unit sets `MemoryDenyWriteExecute=yes`, which blocks Chrome's V8 JIT and kills the renderer. Add a section with diagnosis and the systemd drop-in fix.
d19553a to
c0b9766
Compare
f6544d1 to
bd6a94e
Compare
|
|
||
| switch ($type) { | ||
| case 'remote_chrome': | ||
| $this->addElement('text', 'host', [ |
There was a problem hiding this comment.
So, you conditionally add elements, but no hidden ones? This can lose values on toggling type.
| } | ||
|
|
||
| try { | ||
| $chrome = (HeadlessChromeBackend::createLocal($value)); |
There was a problem hiding this comment.
| $chrome = (HeadlessChromeBackend::createLocal($value)); | |
| $chrome = HeadlessChromeBackend::createLocal($value); |
| cat >/etc/yum.repos.d/google-chrome-stable.repo <<EOF | ||
| [google-chrome-stable] | ||
| name=google-chrome-stable | ||
| baseurl=http://dl.google.com/linux/chrome/rpm/stable/\$basearch |
There was a problem hiding this comment.
| cat >/etc/yum.repos.d/google-chrome-stable.repo <<EOF | |
| [google-chrome-stable] | |
| name=google-chrome-stable | |
| baseurl=http://dl.google.com/linux/chrome/rpm/stable/\$basearch | |
| cat >/etc/yum.repos.d/google-chrome-stable.repo <<'EOF' | |
| [google-chrome-stable] | |
| name=google-chrome-stable | |
| baseurl=http://dl.google.com/linux/chrome/rpm/stable/$basearch |
|
|
||
| yum makecache |
There was a problem hiding this comment.
| yum makecache |
| private function registerEvent($method, $params): void | ||
| { | ||
| if (Logger::getInstance()->getLevel() === Logger::DEBUG) { | ||
| $shortenValues = function ($params) use (&$shortenValues) { |
There was a problem hiding this comment.
Looks like the ideal case for a class method.
|
|
||
| public function isSupported(): bool | ||
| { | ||
| // TODO: Come up with a check |
| public static function getPort() | ||
| { | ||
| return Config::module('pdfexport')->get('chrome', 'port', 9222); | ||
| return $this->locator; |
| return $this->chrome()->getVersion() >= 59; | ||
| return $locator->getFirstSupportedBackend() !== null; | ||
| } catch (Exception $e) { | ||
| Logger::warning("No supported PDF backend available."); |
There was a problem hiding this comment.
| Logger::warning("No supported PDF backend available."); | |
| Logger::warning('No supported PDF backend available.'); |
| fulfill(e.detail); | ||
| }; | ||
|
|
||
| const timeoutId = setTimeout(() => { |
There was a problem hiding this comment.
Can we put this below?
Otherwise it's like, oh, you removeEventListener... which event listener? Ah, yes, there's one below!
Changes
Removed ReactPHP dependency
The module no longer relies on ReactPHP, as such it no longer provides the asynchronous methods to generate PDFs that were never part of the Hook
Introduced backend abstraction
A new backend concept allows different rendering strategies to be plugged in and extended more easily.
Added WebDriver support
Implemented a WebDriver-based backend with support for Chrome and Firefox.
Automatic backend fallback
If a backend fails or is unavailable, the system now automatically falls back to the next available option. (The order of this is currently hardcoded as Webdriver > Remote Chrome > Local Chrome)
New configuration form
Replaced the existing configuration with a new
ipl\Web\Compat\Form-based ConfigForm.Requires
ConfigFormbased onCompatFormicingaweb2#5480firstandhtmlToPdfmethods toPdfexportHookicingaweb2#5491related to Icinga/icingaweb2-module-reporting#275
WebDriver
This module can be configured to connect to a webdriver instance. (Backend)
When a PDF is requested, via the Print PDF button on any site or the one in the reporting module, it sends commands to the WebDriver server in a standardized format.
Each browser has its own driver (like ChromeDriver for Chrome or GeckoDriver for Firefox).
This driver acts as a bridge between your script and the browser.
Browser
The driver sends commands to the browser, which executes them just like a user interaction.
For this to work we require a working chromedriver or geckodriver (firefox) instance.
Adding this to a docker compose file will spin up one for each of the supported webdrivers.
Currently supported features:
Known issues
Chromedriver reports an error with the cover page properties.Is actually related to a deprecated command.