diff --git a/LibreNMS/Data/Store/Rrd.php b/LibreNMS/Data/Store/Rrd.php
index 3cf829b990..dbed308c7f 100644
--- a/LibreNMS/Data/Store/Rrd.php
+++ b/LibreNMS/Data/Store/Rrd.php
@@ -28,10 +28,12 @@ use Illuminate\Support\Str;
use LibreNMS\Config;
use LibreNMS\Data\Measure\Measurement;
use LibreNMS\Exceptions\FileExistsException;
+use LibreNMS\Exceptions\RrdGraphException;
use LibreNMS\Proc;
use LibreNMS\Util\Debug;
use LibreNMS\Util\Rewrite;
use Log;
+use Symfony\Component\Process\Process;
class Rrd extends BaseDatastore
{
@@ -545,25 +547,26 @@ class Rrd extends BaseDatastore
/**
* Generates a graph file at $graph_file using $options
- * Opens its own rrdtool pipe.
+ * Graphs are a single command per run, so this just runs rrdtool
*
- * @param string $graph_file
- * @param string $options
- * @return string|int
+ * @param string $options
+ * @return string
+ * @throws \LibreNMS\Exceptions\FileExistsException
+ * @throws \LibreNMS\Exceptions\RrdGraphException
*/
- public function graph($graph_file, $options)
+ public function graph(string $options): string
{
- if ($this->init(false)) {
- $cmd = $this->buildCommand('graph', $graph_file, $options);
+ $cmd = $this->buildCommand('graph', '-', $options);
+ $process = Process::fromShellCommandline(Config::get('rrdtool') . ' ' . $cmd, $this->rrd_dir);
+ $process->setTimeout(300);
+ $process->setIdleTimeout(300);
+ $process->run();
- $output = implode($this->sync_process->sendCommand($cmd));
-
- d_echo("
$cmd
\ncommand returned ($output)
");
-
- return $output;
- } else {
- return 0;
+ if (! $process->isSuccessful()) {
+ throw new RrdGraphException($process->getErrorOutput(), $process->getExitCode(), $process->getOutput());
}
+
+ return $process->getOutput();
}
public function __destruct()
diff --git a/LibreNMS/Exceptions/RrdGraphException.php b/LibreNMS/Exceptions/RrdGraphException.php
new file mode 100644
index 0000000000..3317ac6ff9
--- /dev/null
+++ b/LibreNMS/Exceptions/RrdGraphException.php
@@ -0,0 +1,44 @@
+.
+ *
+ * @package LibreNMS
+ * @link http://librenms.org
+ * @copyright 2021 Tony Murray
+ * @author Tony Murray
+ */
+
+namespace LibreNMS\Exceptions;
+
+use Exception;
+
+class RrdGraphException extends Exception
+{
+ protected $image_output;
+
+ public function __construct($error, $exit_code, $image_output)
+ {
+ parent::__construct($error, $exit_code);
+ $this->image_output = $image_output;
+ }
+
+ public function getImage()
+ {
+ return $this->image_output;
+ }
+}
diff --git a/includes/html/api_functions.inc.php b/includes/html/api_functions.inc.php
index 1a4aa32b12..654d6a9b2e 100644
--- a/includes/html/api_functions.inc.php
+++ b/includes/html/api_functions.inc.php
@@ -81,8 +81,7 @@ function api_get_graph(array $vars)
{
global $dur; // Needed for callback within graph code
- $auth = '1';
- $base64_output = '';
+ $auth = true;
// prevent ugly error for undefined graphs from being passed to the user
[$type, $subtype] = extract_graph_type($vars['type']);
@@ -99,10 +98,10 @@ function api_get_graph(array $vars)
ob_end_clean();
if ($vars['output'] === 'base64') {
- return api_success(['image' => $base64_output, 'content-type' => get_image_type()], 'image');
+ return api_success(['image' => $image, 'content-type' => get_image_type(Config::get('webui.graph_type'))], 'image');
}
- return response($image, 200, ['Content-Type' => get_image_type()]);
+ return response($image, 200, ['Content-Type' => get_image_type(Config::get('webui.graph_type'))]);
}
function check_bill_permission($bill_id, $callback)
diff --git a/includes/html/functions.inc.php b/includes/html/functions.inc.php
index 7c755886af..6eea38a32a 100644
--- a/includes/html/functions.inc.php
+++ b/includes/html/functions.inc.php
@@ -47,14 +47,6 @@ function var_get($v)
return false;
}
-function data_uri($file, $mime)
-{
- $contents = file_get_contents($file);
- $base64 = base64_encode($contents);
-
- return 'data:' . $mime . ';base64,' . $base64;
-}//end data_uri()
-
function toner2colour($descr, $percent)
{
$colour = \LibreNMS\Util\Colors::percentage(100 - $percent, null);
@@ -465,19 +457,30 @@ function graph_error($text, $color = [128, 0, 0])
{
global $vars;
+ $type = Config::get('webui.graph_type');
if (! Debug::isEnabled()) {
- set_image_type();
+ header('Content-type: ' . get_image_type($type));
}
- $width = $vars['width'] ?? 150;
- $height = $vars['height'] ?? 60;
+ $width = (int) ($vars['width'] ?? 150);
+ $height = (int) ($vars['height'] ?? 60);
- if (Config::get('webui.graph_type') === 'svg') {
+ if ($type === 'svg') {
$rgb = implode(', ', $color);
- $font_size = 20;
- $svg_x = 100;
- $svg_y = min($font_size, $width ? (($height / $width) * $svg_x) : 1);
- echo "";
+ echo <<
+SVG;
} else {
$img = imagecreate($width, $height);
imagecolorallocatealpha($img, 255, 255, 255, 127); // transparent background
@@ -1020,18 +1023,14 @@ function eventlog_severity($eventlog_severity)
}
} // end eventlog_severity
-function set_image_type()
+/**
+ * Get the http content type of the image
+ * @param string $type svg or png
+ * @return string
+ */
+function get_image_type(string $type)
{
- header('Content-type: ' . get_image_type());
-}
-
-function get_image_type()
-{
- if (Config::get('webui.graph_type') === 'svg') {
- return 'image/svg+xml';
- } else {
- return 'image/png';
- }
+ return $type === 'svg' ? 'image/svg+xml' : 'image/png';
}
function get_oxidized_nodes_list()
diff --git a/includes/html/graphs/device/sensor.inc.php b/includes/html/graphs/device/sensor.inc.php
index 3e2923f43e..b5dc26ee5b 100644
--- a/includes/html/graphs/device/sensor.inc.php
+++ b/includes/html/graphs/device/sensor.inc.php
@@ -38,8 +38,8 @@ foreach (dbFetchRows('SELECT * FROM `sensors` WHERE `sensor_class` = ? AND `devi
}//end switch
$sensor_descr_fixed = \LibreNMS\Data\Store\Rrd::fixedSafeDescr($sensor['sensor_descr'], 12);
- $rrd_file = get_sensor_rrd($device, $sensor);
- $rrd_options .= " DEF:sensor{$sensor['sensor_id']}=$rrd_file:sensor:AVERAGE";
+ $rrd_filename = get_sensor_rrd($device, $sensor);
+ $rrd_options .= " DEF:sensor{$sensor['sensor_id']}=$rrd_filename:sensor:AVERAGE";
$rrd_options .= " LINE1:sensor{$sensor['sensor_id']}#$colour:'$sensor_descr_fixed'";
$rrd_options .= " GPRINT:sensor{$sensor['sensor_id']}:LAST:%5.1lf$unit";
$rrd_options .= " GPRINT:sensor{$sensor['sensor_id']}:MIN:%5.1lf$unit";
diff --git a/includes/html/graphs/graph.inc.php b/includes/html/graphs/graph.inc.php
index 3ca8e51422..32572e4e2e 100644
--- a/includes/html/graphs/graph.inc.php
+++ b/includes/html/graphs/graph.inc.php
@@ -2,6 +2,8 @@
use LibreNMS\Config;
+global $debug;
+
// Push $_GET into $vars to be compatible with web interface naming
foreach ($_GET as $name => $value) {
$vars[$name] = $value;
@@ -24,13 +26,12 @@ $legend = $vars['legend'];
$output = (! empty($vars['output']) ? $vars['output'] : 'default');
$from = parse_at_time($_GET['from']) ?: Config::get('time.day');
$to = parse_at_time($_GET['to']) ?: Config::get('time.now');
-$graph_type = (isset($vars['graph_type']) ? $vars['graph_type'] : Config::get('webui.graph_type'));
-
$period = ($to - $from);
-$base64_output = '';
$prev_from = ($from - $period);
-$graphfile = Config::get('temp_dir') . '/' . strgen();
+$graph_image_type = $vars['graph_type'] ?? Config::get('webui.graph_type');
+$rrd_options = '';
+$auth = false;
require Config::get('install_dir') . "/includes/html/graphs/$type/auth.inc.php";
@@ -47,61 +48,75 @@ if ($auth && is_customoid_graph($type, $subtype)) {
// Graph Template Missing");
}
-if ($error_msg) {
+if (! empty($error_msg)) {
// We have an error :(
- graph_error($graph_error);
-} elseif ($auth === null) {
+ graph_error($error_msg);
+
+ return;
+}
+
+if ($auth === null) {
// We are unauthenticated :(
graph_error($width < 200 ? 'No Auth' : 'No Authorization');
-} else {
- // $rrd_options .= " HRULE:0#999999";
- if ($graph_type === 'svg') {
- $rrd_options .= ' --imgformat=SVG';
- if ($width < 350) {
- $rrd_options .= ' -m 0.75 -R light';
- }
- }
- if ($command_only) {
- echo "";
- echo "
RRDTool Command
";
- echo "
";
- echo 'rrdtool ' . Rrd::buildCommand('graph', $graphfile, $rrd_options);
- echo '
';
- $return = Rrd::graph($graphfile, $rrd_options);
- echo "
RRDTool Output
";
- echo "
";
- echo "$return";
- echo '
';
- unlink($graphfile);
- echo '
';
- } elseif ($no_file) {
- graph_error($width < 200 ? 'No Data' : 'No Data file');
- } elseif ($rrd_options) {
- Rrd::graph($graphfile, $rrd_options);
- d_echo($rrd_cmd);
- if (is_file($graphfile)) {
- if (! \LibreNMS\Util\Debug::isEnabled()) {
- set_image_type();
- if ($output === 'base64') {
- $imagedata = file_get_contents($graphfile);
- $base64_output = base64_encode($imagedata);
- } else {
- $fd = fopen($graphfile, 'r');
- fpassthru($fd);
- fclose($fd);
- }
- } else {
- echo `ls -l $graphfile`;
- echo '
';
- }
- unlink($graphfile);
- } elseif (isset($rrd_filename) && ! Rrd::checkRrdExists($rrd_filename)) {
- graph_error($width < 200 ? 'No Data' : 'No Data file');
- } else {
- graph_error($width < 200 ? 'Draw Error' : 'Error Drawing Graph');
- }
- } else {
- graph_error($width < 200 ? 'Def Error' : 'Graph Definition Error');
+ return;
+}
+
+if ($graph_image_type === 'svg') {
+ $rrd_options .= ' --imgformat=SVG';
+ if ($width < 350) {
+ $rrd_options .= ' -m 0.75 -R light';
+ }
+}
+
+// command output requested
+if (! empty($command_only)) {
+ echo "";
+ echo "
RRDTool Command
";
+ echo "
";
+ echo 'rrdtool ' . Rrd::buildCommand('graph', '-', $rrd_options);
+ echo '
';
+ try {
+ Rrd::graph($rrd_options);
+ } catch (\LibreNMS\Exceptions\RrdGraphException $e) {
+ echo "
RRDTool Output
";
+ echo "
";
+ echo $e->getMessage();
+ echo '
';
+ }
+ echo '
';
+
+ return;
+}
+
+// graph sent file not found flag
+if (! empty($no_file)) {
+ graph_error($width < 200 ? 'No Data' : 'No Data file ' . $no_file);
+
+ return;
+}
+
+if (empty($rrd_options)) {
+ graph_error($width < 200 ? 'Def Error' : 'Graph Definition Error');
+
+ return;
+}
+
+// Generating the graph!
+try {
+ $image_data = Rrd::graph($rrd_options);
+
+ // output the graph
+ if (\LibreNMS\Util\Debug::isEnabled()) {
+ echo '
';
+ } else {
+ header('Content-type: ' . get_image_type(Config::get('webui.graph_type')));
+ echo $output === 'base64' ? base64_encode($image_data) : $image_data;
+ }
+} catch (\LibreNMS\Exceptions\RrdGraphException $e) {
+ if (isset($rrd_filename) && ! Rrd::checkRrdExists($rrd_filename)) {
+ graph_error($width < 200 ? 'No Data' : 'No Data file ' . basename($rrd_filename));
+ } else {
+ graph_error($width < 200 ? 'Draw Error' : 'Error Drawing Graph: ' . $e->getMessage());
}
}
diff --git a/includes/html/pages/graphs.inc.php b/includes/html/pages/graphs.inc.php
index ab58655ab5..702438be83 100644
--- a/includes/html/pages/graphs.inc.php
+++ b/includes/html/pages/graphs.inc.php
@@ -92,8 +92,8 @@ if (! $auth) {
$link_array['page'] = 'graphs';
$link = \LibreNMS\Util\Url::generate($link_array);
- echo '';
- echo '' . $text . ' ';
+ echo ' | ';
+ echo '' . $text . '';
echo '';
echo \LibreNMS\Util\Url::lazyGraphTag($graph_array);
echo '';
|