summary | shortlog | log | commit | commitdiff | tree
raw | patch | inline | side by side (parent: a019b6c)
raw | patch | inline | side by side (parent: a019b6c)
author | Bruno Prémont <bonbons@linux-vserver.org> | |
Tue, 10 Feb 2009 20:38:23 +0000 (21:38 +0100) | ||
committer | Florian Forster <octo@huhu.verplant.org> | |
Tue, 10 Feb 2009 20:38:23 +0000 (21:38 +0100) |
Hi,
An update to the graphing interface. (incremental patch attached)
This fixes security complaint by a few browsers when page is accessed
via HTTPS and also makes sure the graphs and lists will load if HTTP
and HTTPS paths differ.
Thanks to Mullet- for spotting this issue.
In addition to the fix above this patch adds support for saving
current graph list to a cookie and appending graph list read from
cookie to the currently displayed list.
A future extension would be to allow saving/loading named graph lists
so multiple list can coexist (pretty useful when monitoring multiple
servers/services)
Bruno
An update to the graphing interface. (incremental patch attached)
This fixes security complaint by a few browsers when page is accessed
via HTTPS and also makes sure the graphs and lists will load if HTTP
and HTTPS paths differ.
Thanks to Mullet- for spotting this issue.
In addition to the fix above this patch adds support for saving
current graph list to a cookie and appending graph list read from
cookie to the currently displayed list.
A future extension would be to allow saving/loading named graph lists
so multiple list can coexist (pretty useful when monitoring multiple
servers/services)
Bruno
contrib/php-collection/browser.js | patch | blob | history | |
contrib/php-collection/functions.php | patch | blob | history | |
contrib/php-collection/index.php | patch | blob | history |
index 9fcdbabe035a5b2146077383587d5ac83cc6f836..6f4d8ec8ddac8dc3d497a8266fc41ef6c3726e93 100644 (file)
}
}
+var req = null;
+
// DHTML helper code to asynchronous loading of content
function loadXMLDoc(url, query) {
if (window.XMLHttpRequest) {
}
// DHTML new-content dispatcher
-function processReqChange() {
+function processReqChange(evt) {
if (req.readyState == 4) {
if (req.status == 200) {
- response = req.responseXML.documentElement;
- method = response.getElementsByTagName('method')[0].firstChild.data;
- result = response.getElementsByTagName('result')[0];
+ var response = req.responseXML.documentElement;
+ var method = response.getElementsByTagName('method')[0].firstChild.data;
+ var result = response.getElementsByTagName('result')[0];
+ req = null;
eval(method + '(result)');
}
}
}
var nextGraphId = 1;
+var graphList = new Array();
function GraphAppend() {
- var graphs = document.getElementById('graphs');
var host_list = document.getElementById('host_list');
var host = host_list.selectedIndex >= 0 ? host_list.options[host_list.selectedIndex].value : '/';
var plugin_list = document.getElementById('plugin_list');
var type = type_list.selectedIndex >= 0 ? type_list.options[type_list.selectedIndex].value : '/';
var tinst_list = document.getElementById('tinst_list');
var tinst = tinst_list.selectedIndex >= 0 ? tinst_list.options[tinst_list.selectedIndex].value : '/';
+ var time_list = document.getElementById('timespan');
+ var timespan = time_list.selectedIndex >= 0 ? time_list.options[time_list.selectedIndex].value : '';
+ var tinyLegend = document.getElementById('tinylegend').checked;
+ var logarithmic = document.getElementById('logarithmic').checked
+ GraphDoAppend(host, plugin, pinst, type, tinst, timespan, tinyLegend, logarithmic);
+}
+
+function GraphDoAppend(host, plugin, pinst, type, tinst, timespan, tinyLegend, logarithmic) {
+ var graphs = document.getElementById('graphs');
if (host != '/' && plugin != '/' && pinst != '/' && type != '/') {
var graph_id = 'graph_'+nextGraphId++;
graph_title = type+(tinst.length > 0 ? '-'+tinst : '')+' of '+plugin+(pinst.length > 0 ? '-'+pinst : '')+' plugin for '+host;
graph_src += '&type_instance='+encodeURIComponent(tinst);
}
- if (document.getElementById('logarithmic').checked)
+ if (logarithmic)
graph_src += '&logarithmic=1';
- if (document.getElementById('tinylegend').checked)
+ if (tinyLegend)
graph_src += '&tinylegend=1';
- if (document.getElementById('timespan').selectedIndex >= 0)
- graph_src += '×pan='+encodeURIComponent(document.getElementById('timespan').options[document.getElementById('timespan').selectedIndex].value);
+ if (timespan)
+ graph_src += '×pan='+encodeURIComponent(timespan);
var now = new Date();
graph_src += '&ts='+now.getTime();
+ graphList.push(graph_id+' '+encodeURIComponent(graph_alt)+(logarithmic ? '&logarithmic=1' : '')+(tinyLegend ? '&tinylegend=1' : '')+'×pan='+encodeURIComponent(timespan));
// Graph container
newGraph = document.createElement('div');
graphs.removeChild(graphs.childNodes[childCnt]);
else if (graphs.childNodes[childCnt].id == 'nograph')
graphs.childNodes[childCnt].style.display = 'block';
+ graphList = new Array();
RefreshButtons();
}
RefreshButtons();
if (graphs.getElementsByTagName('div').length == 1)
document.getElementById('nograph').style.display = 'block';
+
+ var myList = Array();
+ for (i = 0; i < graphList.length; i++)
+ if (graphList[i].substring(0, graph.length) == graph && graphList[i].charAt(graph.length) == ' ')
+ continue;
+ else
+ myList.push(graphList[i]);
+ graphList = myList;
}
}
} else
prevGraph = graphs.childNodes[i];
}
+ for (i = 0; i < graphList.length; i++)
+ if (graphList[i].substring(0, graph.length) == graph && graphList[i].charAt(graph.length) == ' ') {
+ if (i > 0) {
+ var tmp = graphList[i-1];
+ graphList[i-1] = graphList[i];
+ graphList[i] = tmp;
+ }
+ break;
+ }
}
function GraphMoveDown(graph) {
break;
}
}
+ for (i = 0; i < graphList.length; i++)
+ if (graphList[i].substring(0, graph.length) == graph && graphList[i].charAt(graph.length) == ' ') {
+ if (i+1 < graphList.length) {
+ var tmp = graphList[i+1];
+ graphList[i+1] = graphList[i];
+ graphList[i] = tmp;
+ }
+ break;
+ }
+}
+
+function GraphListFromCookie() {
+ if (document.cookie.length > 0) {
+ cookies = document.cookie.split('; ');
+ for (i = 0; i < cookies.length; i++)
+ if (cookies[i].substring(0, 9) == 'graphLst=')
+ return cookies[i].substring(9).split('/');
+ }
+ return new Array();
+}
+
+function GraphSave() {
+ if (graphList.length > 0) {
+ // Save graph list to cookie
+ var str = '';
+ for (i = 0; i < graphList.length; i++) {
+ var g = graphList[i].indexOf(' ');
+ if (i > 0)
+ str += '/';
+ str += graphList[i].substring(g+1);
+ }
+
+ document.cookie = 'graphLst='+str;
+ if (GraphListFromCookie().length == 0)
+ alert("Failed to save graph list to cookie.");
+ else
+ alert("Successfully saved current graph list.");
+ } else {
+ document.cookie = 'graphLst=; expires='+new Date().toGMTString();
+ alert("Cleared saved graph list.");
+ }
+}
+
+function GraphLoad() {
+ // Load graph list from cookie
+ var grLst = GraphListFromCookie();
+ for (i = 0; i < grLst.length; i++) {
+ var host = '';
+ var plugin = '';
+ var pinst = '';
+ var type = '';
+ var tinst = '';
+ var timespan = '';
+ var logarithmic = false;
+ var tinyLegend = false;
+ var graph = grLst[i].split('&');
+ for (j = 0; j < graph.length; j++)
+ if (graph[j] == 'logarithmic=1')
+ logarithmic = true;
+ else if (graph[j] == 'tinylegend=1')
+ tinyLegend = true;
+ else if (graph[j].substring(0, 9) == 'timespan=')
+ timespan = decodeURIComponent(graph[j].substring(9));
+ graph = decodeURIComponent(graph[0]).split('/');
+ host = graph[0];
+ if (graph.length > 1) {
+ var g = graph[1].indexOf('-');
+ if (g >= 0) {
+ plugin = graph[1].substring(0, g);
+ pinst = graph[1].substring(g+1);
+ } else
+ plugin = graph[1];
+ }
+ if (graph.length > 2) {
+ var g = graph[2].indexOf('-');
+ if (g >= 0) {
+ type = graph[2].substring(0, g);
+ tinst = graph[2].substring(g+1);
+ } else
+ type = graph[2];
+ }
+
+ if (host && plugin && type)
+ GraphDoAppend(host, plugin, pinst, type, tinst, timespan, tinyLegend, logarithmic);
+ }
+ if (grLst.length == 0)
+ alert("No list found for loading.");
+ else if (grLst.length != graphList.length)
+ alert("Could not load all graphs, probably damaged cookie.");
}
index f4d07e0a930f877b432859781f91b45300e31f1c..9fb6116f1487ed1d3e99a56154beb6f7d9ca8550 100644 (file)
if ($dent != '.' && $dent != '..' && is_dir($datadir.'/'.$dent) && preg_match(REGEXP_HOST, $dent))
$hosts[] = $dent;
closedir($d);
- }
+ } else
+ error_log('Failed to open datadir: '.$datadir);
$hosts = array_unique($hosts);
usort($hosts, 'collectd_compare_host');
return $hosts;
index 93f1fcf58612625e820fb7a68f9fc9309de1a309..1f788fc968098a46b2514a54f8d6ee39715f0ab2 100644 (file)
print('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'."\n");
print('<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">'."\n");
}
+ $url_base = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off' ? 'https://' : 'http://').$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']).'/';
?>
<head>
<title>Collectd graph viewer</title>
<style type="text/css">
body, html { background-color: #EEEEEE; color: #000000; }
h1 { text-align: center; }
- div.body { margin: auto; width: <?php echo 125+$config['rrd_width'] ?>px; background: #FFFFFF; border: 1px solid #DDDDDD; }
+ div.body { margin: auto; width: <?php echo isset($config['rrd_width']) ? 125+(int)$config['rrd_width'] : 600; ?>px; background: #FFFFFF; border: 1px solid #DDDDDD; }
+ p.error { color: #CC0000; margin: 0em; }
div.selector { margin: 0.5em 2em; }
div.selectorbox { padding: 5px; border: 1px solid #CCCCCC; background-color: #F8F8F8; }
div.selectorbox table { border: none; }
select { width: 100%; }
</style>
<script type="text/javascript">// <![CDATA[
-var dhtml_url = '<?php echo addslashes('http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF']); ?>';
-var graph_url = '<?php echo addslashes('http://'.$_SERVER['HTTP_HOST'].dirname($_SERVER['PHP_SELF']).'/graph.php'); ?>';
+var dhtml_url = '<?php echo addslashes($url_base.basename($_SERVER['PHP_SELF'])); ?>';
+var graph_url = '<?php echo addslashes($url_base.'graph.php'); ?>';
// ]]></script>
- <script type="text/javascript" src="browser.js"></script>
+ <script type="text/javascript" src="<?php echo htmlspecialchars($url_base.'browser.js'); ?>"></script>
</head>
<body onload="ListRefreshHost()"><div class="body">
@@ -135,12 +137,52 @@ var graph_url = '<?php echo addslashes('http://'.$_SERVER['HTTP_HOST'].dirname($
<tr>
<td class="sc" colspan="3"><input id="btnAdd" name="btnAdd" type="button" disabled="disabled" onclick="GraphAppend()" value="Add graph" />
<input id="btnClear" name="btnClear" type="button" disabled="disabled" onclick="GraphDropAll()" value="Remove all graphs" />
- <input id="btnRefresh" name="btnRefresh" type="button" disabled="disabled" onclick="GraphRefresh(null)" value="Refresh all graphs" /></td>
+ <input id="btnRefresh" name="btnRefresh" type="button" disabled="disabled" onclick="GraphRefresh(null)" value="Refresh all graphs" />
+ <input id="btnSave" name="btnSave" type="button" onclick="GraphSave()" value="Save" title="Save graph list to cookie" />
+ <input id="btnLoad" name="btnLoad" type="button" onclick="GraphLoad()" value="Load" title="Load graph list from cookie" /></td>
</tr>
</table>
</div></div>
<div class="graphs"><div id="graphs" class="graphs_t">
- <div id="nograph">Please use above graph selection tool to add graphs to this area.</div>
+ <div id="nograph">Please use above graph selection tool to add graphs to this area.<?php
+ // Config checking
+ if (!isset($config['datadirs']))
+ echo '<p class="error">Config error: $config["datadirs"] is not set</p>';
+ else if (!is_array($config['datadirs']))
+ echo '<p class="error">Config error: $config["datadirs"] is not an array</p>';
+ else if (count($config['datadirs']) == 0)
+ echo '<p class="error">Config error: $config["datadirs"] is empty</p>';
+ else foreach ($config['datadirs'] as $datadir)
+ if (!is_dir($datadir))
+ echo '<p class="error">Config error: $config["datadirs"], '.htmlspecialchars($datadir).' does not exist</p>';
+ if (!isset($config['rrd_width']))
+ echo '<p class="error">Config error: $config["rrd_width"] is not set</p>';
+ else if (10 > (int)$config['rrd_width'])
+ echo '<p class="error">Config error: $config["rrd_width"] is invalid. Integer >= 10 expected</p>';
+ if (!isset($config['rrd_height']))
+ echo '<p class="error">Config error: $config["rrd_height"] is not set</p>';
+ else if (10 > (int)$config['rrd_height'])
+ echo '<p class="error">Config error: $config["rrd_height"] is invalid. Integer >= 10 expected</p>';
+ if (!isset($config['rrd_opts']))
+ echo '<p class="error">Config error: $config["rrd_opts"] is not set</p>';
+ else if (!is_array($config['rrd_opts']))
+ echo '<p class="error">Config error: $config["rrd_opts"] is not an array</p>';
+ if (!isset($config['timespan']))
+ echo '<p class="error">Config error: $config["timespan"] is not set</p>';
+ else if (!is_array($config['timespan']))
+ echo '<p class="error">Config error: $config["timespan"] is not an array</p>';
+ else if (count($config['timespan']) == 0)
+ echo '<p class="error">Config error: $config["timespan"] is empty</p>';
+ else foreach ($config['timespan'] as &$timespan)
+ if (!is_array($timespan) || !isset($timespan['name']) || !isset($timespan['label']) || !isset($timespan['seconds']) || 10 > (int)$timespan['seconds'])
+ echo '<p class="error">Config error: $config["timespan"], invalid entry found</p>';
+ if (!is_null($config['collectd_sock']) && strncmp('unix://', $config['collectd_sock'], 7) != 0)
+ echo '<p class="error">Config error: $config["collectd_sock"] is not valid</p>';
+ if (!defined('RRDTOOL'))
+ echo '<p class="error">Config error: RRDTOOL is not defined</p>';
+ else if (!is_executable(RRDTOOL))
+ echo '<p class="error">Config error: RRDTOOL ('.htmlspecialchars(RRDTOOL).') is not executable</p>';
+ ?></div>
</div></div>
</div></body>
</html><?php