diff options
Diffstat (limited to 'web/nms.gathering.org/nms2/index.html')
-rw-r--r-- | web/nms.gathering.org/nms2/index.html | 500 |
1 files changed, 435 insertions, 65 deletions
diff --git a/web/nms.gathering.org/nms2/index.html b/web/nms.gathering.org/nms2/index.html index a9c33c4..7d49c33 100644 --- a/web/nms.gathering.org/nms2/index.html +++ b/web/nms.gathering.org/nms2/index.html @@ -1,68 +1,438 @@ <!DOCTYPE html> <html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> - <meta charset="utf-8"> - <title>NMS2</title> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <meta name="description" content=""> - <meta name="author" content=""> - - <link href="css/bootstrap.min.css" rel="stylesheet"> - <link href="css/bootstrap-responsive.min.css" rel="stylesheet"> - <link href="css/slider.css" rel="stylesheet"> - <style type="text/css"> - body { - padding-top: 60px; - padding-bottom: 40px; - } - .sidebar-nav { - padding: 9px 0; - } - - </style> - - <!-- HTML5 shim, for IE6-8 support of HTML5 elements --> - <!--[if lt IE 9]> - <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> - <![endif]--> - - <style type="text/css"></style></head> - <body> - <div class="navbar navbar-inverse navbar-fixed-top"> - <div class="navbar-inner"> - <div class="container-fluid"> - <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> - <span class="icon-bar"> - </span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - </a> - <div class="nav-collapse collapse"> - <p class="navbar-text pull-right" id="speed">Foobar</p> - <ul class="nav"> - <li class="active"id="nav-param"><a href="#params" onclick="showSwitches()">Show Switches</a></li> - <li id="nav-home"><a href="#about" onclick="showHome()">About</a></li> - </ul> - </div><!--/.nav-collapse --> - </div> - </div> - </div> - - <div class="container-fluid"> - <div class="row-fluid"> - <div class="span12"> - <div class="input-append"> - <select onchange="switchChange()" id="switch-list"></select> - <select onchange="portChange()" id="port-list"></select> - <input type="text" id="switch-info"> - </div> - <textarea id="foo" rows=20 cols=80 class="input-block-level"> </textarea> - </div> - </div><!--/row--> - </div><!--/.fluid-container--> - </div> - <script src="js/jquery-1.10.2.min.js"></script> - <script src="js/bootstrap.min.js"></script> - <script src="js/nms2.js"></script> - </body> + <meta charset="utf-8"> + <title>NMS2</title> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <meta name="description" content=""> + <meta name="author" content=""> + + <script src="js/jquery-1.10.2.min.js"></script> + <!--<script src="http://cdn.jsdelivr.net/qtip2/2.2.1/jquery.qtip.min.js"></script>--> + + <link href="css/bootstrap.min.css" rel="stylesheet"> + <link href="css/bootstrap-responsive.min.css" rel="stylesheet"> + <link href="css/slider.css" rel="stylesheet"> + <!--<link src="http://cdn.jsdelivr.net/qtip2/2.2.1/jquery.qtip.min.css" rel="stylesheet">--> + <style type="text/css"> + body { + padding-top: 60px; + padding-bottom: 40px; + } + .sidebar-nav { + padding: 9px 0; + } + + #canvas { + background-image: url('http://nms.tg15.gathering.org/tg15-salkart.png'); + } + + #tooltip { + position: absolute; + left: 110px; + top: 110px; + border: 1px solid #FF0000; + } + </style> + + <!-- HTML5 shim, for IE6-8 support of HTML5 elements --> + <!--[if lt IE 9]> + <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> + <![endif]--> + + <script type="text/javascript"> + $(document).ready(function() { + + var switches = {}; + var selectedSwitch = null; + var selectedPort = null; + var mapSize = null; + + var activeHover = null; + + /* Bind: drop-down::switch-list -> onChange() + -------------------------------------------- */ + $('#switch-list').change(function() { + selectedSwitch = $("#switch-list option:selected").text(); + updatePortList(); + //sumPorts(selectedSwitch); + }); + + /* Bind: drop-down::port-list -> onChange(); + ------------------------------------------- */ + $('#port-list').change(function() { + selectedPort = $("#port-list option:selected").text(); + showPortdata(); + }); + + $("#canvas").mousemove(function( event ) { + var x = event.pageX-$('#canvas').offset().left; + var y = event.pageY-$('#canvas').offset().top; + jQuery.each(switches, function(_switch, data) { + var sx = parseInt(data['x']); + var sy = parseInt(data['y']); + if (x>=sx && y>=sy && x <= sx+data['width'] && y <= sy+data['height']) { + $('#tooltip').css({backgroundColor: '#c2c2c2', bawidth: '100px', height: 'auto', visibility: 'visible', left: x+5, top: y-5}); + $('#tooltip').html(_switch + '<br>'); + + activeHover = _switch; + /* + $('#tooltip').qtip({ // Grab some elements to apply the tooltip to + position: { type: 'absolute'}, + position: { adjust: { x: 100, y: 100 } }, + content: { + text: 'My common piece of text here' + } + }) + */ + return true; + } else { activeHover = null; } + }); + }); + + /* ------------ Functions below -------------- */ + + function byteCount(bytes) { + var units = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']; + i = 0; + while (bytes > 1024) { bytes = bytes / 1024; i++; } + return bytes.toFixed(1) + units[i]; + } + + function sum(arr) { + arr.reduce( + function(prev,current){ + return +(current[1]) + prev; + }, 0 + ); + } + + function hslToRgb(h, s, l){ + var r, g, b; + + if(s == 0){ + r = g = b = l; // achromatic + }else{ + var hue2rgb = function hue2rgb(p, q, t){ + if(t < 0) t += 1; + if(t > 1) t -= 1; + if(t < 1/6) return p + (q - p) * 6 * t; + if(t < 1/2) return q; + if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; + return p; + } + + var q = l < 0.5 ? l * (1 + s) : l + s - l * s; + var p = 2 * l - q; + r = hue2rgb(p, q, h + 1/3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1/3); + } + + return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; + } + + function rgbToHsl(r, g, b){ + r /= 255, g /= 255, b /= 255; + var max = Math.max(r, g, b), min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + + if(max == min){ + h = s = 0; // achromatic + }else{ + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch(max){ + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + + return [h, s, l]; + } + + function numberToColorHsl(i) { + // as the function expects a value between 0 and 1, and red = 0° and green = 120° + // we convert the input to the appropriate hue value + var hue = i * 1.2 / 360; + // we convert hsl to rgb (saturation 100%, lightness 50%) + var rgb = hslToRgb(hue, 1, .5); + // we format to css value and return + return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')'; + } + + + + function sumPorts(_switch) { + var totalIn = 0; + var totalOut = 0; + var avgTotalIn = []; + var avgTotalOut = []; + var foundUplinks = 0; + + if (_switch in switches && 'ports' in switches[_switch] ) { + jQuery.each(switches[_switch]['ports'], function(port, portdata) { + if ('history' in portdata && $.inArray(port, ['ge-0/0/44', 'ge-0/0/45', 'ge-0/0/46', 'ge-0/0/47']) > -1) { + var timeframe = parseInt(portdata['time'])-parseInt(portdata['history']['time']); + + // byte == 1 octett + In = (parseInt(portdata['ifhcinoctets']) - parseInt(portdata['history']['ifhcinoctets'])) / timeframe; + Out = (parseInt(portdata['ifhcoutoctets']) - parseInt(portdata['history']['ifhcoutoctets'])) / timeframe; + + if (In > 0 || Out > 0) { + totalIn += In; + avgTotalIn.push(In); + + totalOut += Out; + avgTotalOut.push(Out); + + foundUplinks++; + } + } + }); + + if (totalIn > 0 && totalOut > 0) { + var avgIn = sum(avgTotalIn)/avgTotalIn.length; + var avgOut = sum(avgTotalOut)/avgTotalOut.length; + + switches[_switch]['average'] = {IN: avgIn, OUT: avgOut}; + switches[_switch]['load'] = {IN: totalIn/foundUplinks, OUT: totalOut/foundUplinks}; + } + } + } + + function showPortdata() { + if(selectedSwitch && selectedPort) { + var portdata = switches[selectedSwitch]['ports'][selectedPort]; + var timeframe = parseInt(portdata['time'])-parseInt(portdata['history']['time']); + + // byte == 1 octett + inPerSec = (parseInt(portdata['ifhcinoctets']) - parseInt(portdata['history']['ifhcinoctets'])) / timeframe; + outPerSec = (parseInt(portdata['ifhcoutoctets']) - parseInt(portdata['history']['ifhcoutoctets'])) / timeframe; + + $('#switchinfo').val(''); + $('#switchinfo').val($('#switchinfo').val() + 'IN: ' + byteCount(inPerSec) + '/s\n'); + $('#switchinfo').val($('#switchinfo').val() + 'Out: ' + byteCount(outPerSec) + '/s\n'); + + //jQuery.each(switches[selectedSwitch]['ports'][selectedPort], function(key, val) { + // $('#switchinfo').val($('#switchinfo').val() + inPerSec + '\n'); + //}); + + console.log(switches); + } + } + + function updatePortList() { + if(selectedSwitch) { + $('#port-list').empty() + jQuery.each(switches[selectedSwitch]['ports'], function(port, val) { + $('#port-list').append( + $('<option></option>').val(port).html(port) + ); + }); + } + } + + function updateSwitchList() { + jQuery.each(switches, function(_switch, val) { + found = false; + $('#switch-list option').each(function(){ + if (this.value == _switch) { + found = true; + return false; + } + }); + + if (!found) { + $('#switch-list').append( + $('<option></option>').val(_switch).html(_switch) + ); + } + }); + + // var firstItem = $('#switch-list')[0][0].value; + selectedSwitch = $("#switch-list option:selected").text(); + + updatePortList(); + selectedPort = $("#port-list option:selected").text(); + + showPortdata(); + } + + Object.size = function(obj) { + var size = 0, key; + for (key in obj) { + if (obj.hasOwnProperty(key)) size++; + } + return size; + }; + + function refreshInfra(func) { + /* Note: + These ajax-requests are chained in their own success + because the "inside ajax" can not be run before the predecessor + is completed. This is because the nested ajax-calls loops over + data that will otherwise not be found. + */ + + /* Background: Update switchlist + ------------------------------- */ + $.ajax({ + type: "GET", + url: "/switches-json2.pl", + dataType: "text", + success: function (data, textStatus, jqXHR) { + decoded = JSON.parse(data); + jQuery.each(decoded['switches'], function(_switch, val) { + switches[_switch] = val; + switches[_switch]['speed'] = 125000000; // 1Gbit In bytes! BYYYYTE!!! Geez louise! + }); + console.log(switches); + /* Background: Update live port-data/port-list + --------------------------------------------- */ + $.ajax({ + type: "GET", + url: "/port-state.pl", + dataType: "text", + success: function (data, textStatus, jqXHR) { + var switchdata = JSON.parse(data); + jQuery.each(switchdata, function(_switch, val) { + switches[_switch]['ports'] = {}; + + jQuery.each(val['ports'], function(port, val) { + switches[_switch]['ports'][port] = val; + }); + }); + /* Background: Update port-history + --------------------------------- */ + $.ajax({ + type: "GET", + url: "/port-state.pl?time=5m", + dataType: "text", + success: function (data, textStatus, jqXHR) { + var switchdata = JSON.parse(data); + jQuery.each(switchdata, function(_switch, val) { + jQuery.each(val['ports'], function(port, val) { + switches[_switch]['ports'][port]['history'] = val; + }); + }); + if(typeof func != 'undefined') + func(); + } + }) + } + }); + } + }); + } + + function randint(min, max) { + return Math.floor(Math.random() * (max - min)) + min; + } + + Array.max = function( array ){ + return Math.max.apply( Math, array ); + }; + + window.addEventListener('resize', resizeCanvas, false); + + function drawMap() { + if (Object.size(switches) > 0) { + var c = $("#canvas")[0]; + var ctx = c.getContext("2d"); + ctx.clearRect(0, 0, c.width, c.height); + jQuery.each(switches, function(_switch, data) { + sumPorts(_switch); + if("load" in switches[_switch]) { + var perc = 100.0/parseInt(data['speed']); + var throughput = Array.max([switches[_switch]['load']['IN'], switches[_switch]['load']['OUT']]); + var percentage = throughput*perc; + ctx.fillStyle=numberToColorHsl( 100-percentage ); + ctx.fillRect(parseInt(data['x']), parseInt(data['y']), data['width'], data['height']); + } + }); + if(activeHover) { + ctx.beginPath(); + ctx.moveTo(parseInt(switches[activeHover]['x']), parseInt(switches[activeHover]['y'])); + ctx.lineTo(switches[activeHover]['width'], switches[activeHover]['height']); + ctx.stroke(); + } + } + } + function resizeCanvas() { + canvas.width = mapSize[0]; + canvas.height = mapSize[1]; + + var ref = window.setInterval(function() { drawMap(); }, 50); + } + + function init() { + var url = $('#canvas').css('background-image').slice(4, -1); + + var bgImg = $('<img />'); + bgImg.hide(); + bgImg.bind('load', function() + { + mapSize = [$(this).width(), $(this).height()]; + // After we've loaded the map into a hidden <img> to measure the size + // we can resize the canvas accordingly. The resize function contains all our draw stuff. + resizeCanvas(); + }); + $('body').append(bgImg); + bgImg.attr('src', url); + + // Fire only once, with a parameter to update the switch-list. + // This will flicker the drop-down once but giving us a function + // to refresh "infra" in the background retrieving data in real time without affecting the UI. + refreshInfra(updateSwitchList); + } + init(); + + }); + </script> + + <style type="text/css"></style></head> + <body> + <div class="navbar navbar-inverse navbar-fixed-top"> + <div class="navbar-inner"> + <div class="container-fluid"> + <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> + <span class="icon-bar"> + </span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </a> + <div class="nav-collapse collapse"> + <p class="navbar-text pull-right" id="speed">Foobar</p> + <ul class="nav"> + <li class="active"id="nav-param"><a href="#params" onclick="showSwitches()">Show Switches</a></li> + <li id="nav-home"><a href="#about" onclick="showHome()">About</a></li> + </ul> + </div><!--/.nav-collapse --> + </div> + </div> + </div> + + <div class="container-fluid"> + <div class="row-fluid"> + <div class="span12"> + <div class="input-append"> + <select id="switch-list"></select> + <select id="port-list"></select> + <br> + + <!--<textarea id="switchinfo" rows=20 cols=80 class="input-block-level"> </textarea>--> + <canvas id="canvas"></canvas> + </div> + </div><!--/row--> + </div><!--/.fluid-container--> + </div> + <script src="js/bootstrap.min.js"></script> + <script src="js/nms2-lib.js"></script> + <script src="js/nms2.js"></script> + + <div id="tooltip"></div> + </body> </html> |