Files
goldpinger/static/index.html
tgetachew 14ea96999a add external probes
Signed-off-by: kitfoman <thaddeusgetachew@gmail.com>

make timeout flags backwards compatible

Signed-off-by: kitfoman <thaddeusgetachew@gmail.com>
2022-05-08 22:02:09 -04:00

491 lines
21 KiB
HTML

<!--
Copyright 2018 Bloomberg Finance L.P.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Goldpinger</title>
<!-- Utilities -->
<script type="text/javascript" src="static/jquery/3.1.0/jquery.min.js"></script>
<!-- Sigma.js -->
<script type="text/javascript" src="static/sigma.js/1.1.0/sigma.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.exporters.svg.min.js"></script>:
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.layout.forceAtlas2.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.neo4j.cypher.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.parsers.cypher.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.parsers.gexf.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.parsers.json.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.pathfinding.astar.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.plugins.animate.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.plugins.dragNodes.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.plugins.filter.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.plugins.neighborhoods.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.plugins.relativeSize.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.renderers.customEdgeShapes.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.renderers.customShapes.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.renderers.edgeLabels.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.renderers.parallelEdges.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.renderers.snapshot.min.js"></script>
<script type="text/javascript" src="static/sigma.js/1.1.0/plugins/sigma.statistics.HITS.min.js"></script>
<!-- Bootstrap -->
<link rel="stylesheet" href="static/bootstrap/3.3.7/css/bootstrap.min.css" crossorigin="anonymous">
<link rel="stylesheet" href="static/bootstrap/3.3.7/css/bootstrap-theme.min.css" crossorigin="anonymous">
<script src="static/bootstrap/3.3.7/js/bootstrap.min.js" crossorigin="anonymous"></script>
<style type="text/css">
body {
margin: 0;
}
#container {
}
#graph-container {
position: absolute;
top: 0px;
bottom: 0px;
left: 0px;
right: 0px;
/*background-color: white;*/
}
</style>
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Goldpinger</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Graph</a></li>
<li><a href="#" id="show-data">Data</a></li>
<li><a href="#" id="show-heatmap">Heatmap</a></li>
<li><a href="check_all" >Raw</a></li>
<li><a href="metrics" >Metrics</a></li>
</ul>
<div class="navbar-form navbar-left" role="search">
<div class="form-group">
<!-- <input id="timeout" type="number" step="any" class="form-control" placeholder="5.0" value="5.0"> -->
</div>
<button id="reload-graph" class="btn btn-default">reload</button>
</div>
</div>
</div>
</nav>
<div class="container">
<div id="graph-container"></div>
</div>
</div>
<div id="modal-window-code" class="modal fade bs-example-modal-lg" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="modal-title">title</h4>
</div>
<div class="modal-body" id="modal-body">
body
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<div id="modal-window-heatmap" class="modal fade bs-example-modal-lg" tabindex="-2" role="dialog" aria-labelledby="myLargeModalLabel">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="modal-title">Heatmap</h4>
</div>
<div class="modal-body">
<div id="heatmap-body" style="padding: 10px"></div>
<div class="input-group">
<span class="input-group-addon" style="width: 200px">Good threshold</span>
<input id="t0" type="number" step="1" class="form-control" placeholder="2" value="2">
<span class="input-group-addon">milliseconds</span>
</div>
<div class="input-group">
<span class="input-group-addon" style="width: 200px">Warning threshold</span>
<input id="t1" type="number" step="1" class="form-control" placeholder="5" value="5">
<span class="input-group-addon">milliseconds</span>
</div>
<div class="input-group">
<span class="input-group-addon" style="width: 200px">Problem threshold</span>
<input id="t2" type="number" step="1" class="form-control" placeholder="100" value="100">
<span class="input-group-addon">milliseconds</span>
</div>
</div>
<div class="modal-footer">
<button class="btn btn-success" id="update-heatmap" type="button">refresh</button>
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<script>
var getHeatmapUrl = function(){
return "heatmap.png?"
+ "t0=" + Number($("#t0").val())
+ "&t1=" + Number($("#t1").val())
+ "&t2=" + Number($("#t2").val())
+ "&now=" + Date.now();
}
var fetchJSON = function(url) {
return new Promise(function(resolve, reject) {
console.log("calling " + url);
var req = new XMLHttpRequest();
req.open('get', url, true);
req.responseType = 'json';
req.onload = function() {
if (req.status == 200) {
resolve(req.response);
} else {
reject({
status: req.status,
response: req.response,
statusText: req.statusText
});
}
};
req.send();
});
};
var prepareJSON = function(subject){
return "<code style='white-space: pre;'>"
+ JSON.stringify(subject, undefined, 4)
+ "</code>"
}
var loadingDialog = function(enable){
$('#modal-title').html("Loading");
$('#modal-body').html(prepareJSON({stuff:{will_be_there:true, soon: "Math.random() > 0.5"}}));
// show the things
if (enable){
$('#modal-window-code').modal('show');
} else {
$('#modal-window-code').modal('hide');
}
};
var global_data = undefined;
var s; // the sigma graph
var main = function(timeout){
timeout = timeout || Number($("#timeout").val()) || 5.0;
loadingDialog(true);
fetchJSON("check_all?timeout="+timeout)
.then(function(data){
loadingDialog(false);
//console.log(data);
global_data = data;
// prepare nodes
var nodes = [];
var podIPs = [];
var resp = data.responses;
for (let podIP in resp) {
let value = resp[podIP];
nodes.push({
"label": podIP + " (" + value.HostIP + ")",
"id": podIP,
"x": 0,
"y": 0,
_data: value,
});
podIPs.push(podIP);
};
// prepare the edges
var edges = [];
var resp = data.responses;
for (let callId in resp) {
// If there was an error, the response can be undefined,
// especially if there was a timeout/context exceeded
if (resp[callId].response !== undefined) {
var call = resp[callId].response['podResults'];
if (typeof call !== 'string'){
for (let target in call) {
edges.push({
source: callId,
target: target,
_data: call[target]
});
};
}
}
};
console.log(edges);
console.log(nodes);
// if running goldpinger with PING_NUMBER, then we need to add nodes for the edges
// that are not reporting but are reported to
edges.forEach(function(edge) {
[edge.source, edge.target].forEach(function(value) {
if (podIPs.indexOf(value) == -1){
nodes.push({
"label": value,
"id": value,
"x": 0,
"y": 0,
_data: {},
});
podIPs.push(value);
}
})
})
console.log(nodes);
var probeResultsNodes = [];
if ('probeResults' in data) {
var yoffset = 0;
for (let checkedHost in data.probeResults) {
let value = data.probeResults[checkedHost];
var allOk = true;
for (let pod in value) {
for (var i = 0; i < value[pod].length; i++){
var elapsed = 0;
var podData = value[pod][i];
if ('response-time-ms' in podData) {
elapsed = podData['response-time-ms'];
}
var podOk = (!('error' in podData));
allOk = allOk && podOk
edges.push({
source: pod,
target: checkedHost,
_data: {
"OK": podOk,
"elapsed": elapsed,
"isprobeResultsNode": true,
}
});
}
}
value["OK"] = allOk
probeResultsNodes.push({
"label": checkedHost,
"id": checkedHost,
"x": 0,
"y": 0,
_data: value,
});
}
}
// build the actual graph
s = new sigma({
graph: {
nodes: [],
edges: []
},
renderer: {
container: document.getElementById('graph-container'),
type: 'canvas'
},
settings: {
edgeLabelSize: 'proportional',
minArrowSize: 7,
minNodeSize: 10,
sideMargin: 0.45
}
});
// generate the nodes on the graph
nodes.forEach(function(node, i, a){
node.x = Math.cos(Math.PI * 2 * i / a.length);
node.y = Math.sin(Math.PI * 2 * i / a.length);
node.size = 10;
node.color = "#4CC40B";
if (!node._data.OK) {
node.color = "red";
}
//console.log(node);
s.graph.addNode(node);
});
// generate any dns nodes on the graph
probeResultsNodes.forEach(function(node, i, a){
node.x = 2;
node.y = (0.6 * i / a.length) - 0.8;
node.size = 10;
node.color = "#4CC40B";
if (!node._data.OK) {
node.color = "red";
}
s.graph.addNode(node);
});
// generate the edges
edges.forEach(function(edge, i){
var color = "#ccc";
var type = "curvedArrow";
if (edge.source == edge.target){
color = "gray";
type = "curve";
}
if (!edge._data.OK) {
color = "red";
}
if ("isprobeResultsNode" in edge._data) {
type = "dashed";
}
var edge = {
id: "e" + i,
source: edge.source,
target: edge.target,
type: type,
color: color,
label: edge._data.elapsed,
size: 7
}
//console.log(edge);
s.graph.addEdge(edge)
});
console.log(s.graph.nodes());
console.log(s.graph.edges());
s.refresh();
var hideNotTouching = function(dst){
s.graph.edges().forEach(function(edge){
if (dst == undefined) {
// revert everything to the original state
if (edge._color){
edge.color = edge._color;
delete edge._color;
}
} else if (edge.source != dst){
// hide
if (!edge._color){
edge._color = edge.color;
}
edge.color = "#faf8f6";
} else {
// show
if (edge._color) {
edge.color = edge._color;
}
}
});
s.refresh();
}
s.bind("clickNode", function (e) {
var node = e.data.node;
hideNotTouching(node.id);
// fill the voids
$('#modal-title').html(node.id);
$('#modal-body').html(prepareJSON(node._data));
// show the things
$('#modal-window-code').modal('show');
});
s.bind("clickStage", function (e) {
hideNotTouching();
});
s.bind("clickEdge", function (e) {
var edge = e.data.edge;
console.log(edge);
// fill the voids
$('#modal-title').html(edge.id);
$('#modal-body').html(prepareJSON(edge._data));
// show the things
$('#modal-window-code').modal('show');
});
})
.catch(function(err){
console.error(err);
$('#modal-title').html("Error");
$('#modal-body').html(prepareJSON(err));
$('#modal-window-code').modal('show');
});
};
main();
$("#show-data").click(function (e) {
// fill the voids
$('#modal-title').html("check_all");
$('#modal-body').html(prepareJSON(global_data));
// show the things
$('#modal-window-code').modal('show');
});
$("#reload-graph").click(function (e) {
s.kill();
main();
});
$("#show-heatmap").click(function (e) {
updateHeatmap();
$('#modal-window-heatmap').modal('show');
});
var updateHeatmap = function(){
$('#heatmap-body').html(
'<img src="' + getHeatmapUrl() + '" />'
);
}
$("#update-heatmap").click(function (e) {
updateHeatmap();
});
</script>
</body>
</html>