aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--web/nms.gathering.org/nms2/index.html23
-rw-r--r--web/nms.gathering.org/nms2/js/nms-color-util.js54
-rw-r--r--web/nms.gathering.org/nms2/js/nms-map-handlers.js283
-rw-r--r--web/nms.gathering.org/nms2/js/nms.js600
-rwxr-xr-xweb/nms.gathering.org/ping-json2.pl2
-rwxr-xr-xweb/nms.gathering.org/port-state.pl16
-rwxr-xr-xweb/nms.gathering.org/switch-comment.pl25
7 files changed, 625 insertions, 378 deletions
diff --git a/web/nms.gathering.org/nms2/index.html b/web/nms.gathering.org/nms2/index.html
index 211bcf9..aeda611 100644
--- a/web/nms.gathering.org/nms2/index.html
+++ b/web/nms.gathering.org/nms2/index.html
@@ -57,6 +57,7 @@
<li><a href="#uplink" onclick="setUpdater(handler_uplinks)">Uplink map</a></li>
<li><a href="#temp" onclick="setUpdater(handler_temp)">Temperature map</a></li>
<li><a href="#traffic" onclick="setUpdater(handler_traffic)">Traffic map</a></li>
+ <li><a href="#comment" onclick="setUpdater(handler_comment)">Comment spotter</a></li>
<li><a href="#disco" onclick="setUpdater(handler_disco)">DISCO</a></li>
<li class="divider"> </li>
<li><a href="#" onclick="toggleNightMode()" title="Add 'nightMode' anywhere in the url to auto-enable">Toggle Night Mode</a></li>
@@ -86,7 +87,7 @@
</li>
</ul>
<ul class="nav navbar-nav navbar-right">
- <li><p id="speed" class="navbar-text" title="Client port speed"></p></li>
+ <li><p id="speed" class="navbar-text" title="Client port speed / Total port speed"></p></li>
</ul>
</div><!--/.nav-collapse -->
</div>
@@ -135,6 +136,7 @@
<button class="btn" onclick="document.getElementById('nowPickerBox').style.display = 'none';">Cancel</button>
</div>
</div>
+ <div style="position: fixed; z-index: 120;">
<div id="info-switch-parent" class="panel panel-default" style="display: none; backgroun:silver; position: fixed; z-index: 120;">
<div class="panel-heading"><h3 class="panel-title"
id="info-switch-title"></h3></div>
@@ -144,6 +146,7 @@
</div>
</div>
</div>
+ </div>
<div id="aboutBox" class="panel panel-default" style="display: none; position: fixed; z-index: 100;">
<div class="panel-heading"><h3 class="panel-title">Welcome to NMS
<button type="button" class="close" aria-labe="Close" onclick="document.getElementById('aboutBox').style.display = 'none';" style="float: right;"><span aria-hidden="true">&times;</span></button></h3></div>
@@ -170,12 +173,9 @@
not used)</li>
<li>Add DHCP map</li>
<li>Add magic map (combined map of sorts)</li>
- <li>Add better control panel stuff (Review timers, change some, etc)</li>
<li>Adjust updatePorts() frequency based on necessity (1sec
updates is overkill for regular operation, but needed for time
travel)</li>
- <li>Fix legend display (There's a legend for all handlers, but
- it's currently hidden beneath the canvas)</li>
<li>More info on switches: Port state, possibly link time
trends)</li>
<li>Moving switches around (like ping.html + edit)</li>
@@ -185,16 +185,21 @@
</ul>
<h3>Todo for backend:</h3>
<ul>
- <li>Fix horrible SQL :D</li>
+ <li>IPv6 support</li>
<li>Close SQL injections (IT'S WIDE OPEN BECAUSE WHY NOT THAT'S NEVER A PROBLEM)</li>
- <li>Fix SNMP-fetcher so it gets ifXTable and at least ifOperStatus from ifTable. Possibly other tweaks.</li>
+ <li>Consider time log of DHCP (right now it just stores the
+ most recent timestamp, making time travel impossible)</li>
+ <li>Fix SNMP-fetcher so it gets ifXTable and at least ifOperStatus from ifTable. Don't request the entire ifXTable if we can avoid it. Possibly other tweaks.</li>
<li>Support for adding switches through an API, not just pure SQL.</li>
+ <li>Comments. Allow two type of comments: switch-specific
+ comments and "global". Possibly ticket-like support. Ooooooooh,
+ jira support? :P </li>
<li>Integrate with FAP</li>
<li>Clean up old interfaces</li>
<li>Review various agents/tools</li>
<li>Improve cache headers</li>
- <li>Consider time log of DHCP (right now it just stores the
- most recent timestamp, making time travel impossible)</li>
+ <li>Re-test the SQL schema. It's been modified and works fine
+ on my laptop, but I need to dump it, commit it and test it.</li>
<li>Munin plugin for ports.</li>
</ul>
</div>
@@ -228,6 +233,8 @@
<script src="js/jquery.min.js" type="text/javascript"></script>
<script src="js/bootstrap.min.js" type="text/javascript"></script>
<script type="text/javascript" src="js/nms.js"></script>
+ <script type="text/javascript" src="js/nms-color-util.js"></script>
+ <script type="text/javascript" src="js/nms-map-handlers.js"></script>
<script type="text/javascript">
initNMS();
</script>
diff --git a/web/nms.gathering.org/nms2/js/nms-color-util.js b/web/nms.gathering.org/nms2/js/nms-color-util.js
new file mode 100644
index 0000000..28f7e1b
--- /dev/null
+++ b/web/nms.gathering.org/nms2/js/nms-color-util.js
@@ -0,0 +1,54 @@
+
+function gradient_from_latency(latency_ms, latency_secondary_ms)
+{
+ if (latency_secondary_ms === undefined) {
+ return rgb_from_latency(latency_ms);
+ }
+ return 'linear-gradient(' +
+ rgb_from_latency(latency_ms) + ', ' +
+ rgb_from_latency(latency_secondary_ms) + ')';
+}
+
+function rgb_from_latency(latency_ms)
+{
+ if (latency_ms === null || latency_ms === undefined) {
+ return '#0000ff';
+ }
+
+ var l = latency_ms / 40.0;
+ if (l >= 2.0) {
+ return 'rgb(255, 0, 0)';
+ } else if (l >= 1.0) {
+ l = 2.0 - l;
+ l = Math.pow(l, 1.0/2.2);
+ l = Math.floor(l * 255.0);
+ return 'rgb(255, ' + l + ', 0)';
+ } else {
+ l = Math.pow(l, 1.0/2.2);
+ l = Math.floor(l * 255.0);
+ return 'rgb(' + l + ', 255, 0)';
+ }
+}
+
+/*
+ * Give us a color from blue (0) to red (100).
+ */
+function rgb_from_max(x)
+{
+ x = x/100;
+ var colorred = 255 * x;
+ var colorblue = 255 - colorred;
+
+ return 'rgb(' + Math.floor(colorred) + ", 0, " + Math.floor(colorblue) + ')';
+}
+
+/*
+ * Return a random-ish color (for testing)
+ */
+function getRandomColor()
+{
+ var i = Math.round(Math.random() * 5);
+ var colors = [ "white", "red", "pink", "yellow", "orange", "green" ];
+ return colors[i];
+}
+
diff --git a/web/nms.gathering.org/nms2/js/nms-map-handlers.js b/web/nms.gathering.org/nms2/js/nms-map-handlers.js
new file mode 100644
index 0000000..762788a
--- /dev/null
+++ b/web/nms.gathering.org/nms2/js/nms-map-handlers.js
@@ -0,0 +1,283 @@
+/*
+ * Map handlers/updaters for NMS.
+ *
+ * These are functions used to determine how the map should look in NMS.
+ * They represent vastly different information, but in a uniform way. I
+ * suppose this is the c++-type of object orientation...
+ *
+ * The idea is that these updaters only parse information that's fetched by
+ * NMS - they do not request additional information. E.g., ping data is
+ * always present, but until the ping-handler is active, it isn't
+ * displayed. This might seem redundant, but it means any handler can
+ * utilize information from any aspect of NMS, and thus opens NMS up to the
+ * world of intelligent maps base don multiple data sources.
+ */
+
+/*
+ * Handlers. "updater" is run periodically when the handler is active, and
+ * "init" is run once when it's activated.
+ */
+
+var handler_uplinks = {
+ updater:uplinkUpdater,
+ init:uplinkInit,
+ name:"Uplink map"
+};
+
+var handler_temp = {
+ updater:tempUpdater,
+ init:tempInit,
+ name:"Temperature map"
+};
+
+var handler_ping = {
+ updater:pingUpdater,
+ init:pingInit,
+ name:"IPv4 Ping map"
+};
+
+var handler_traffic = {
+ updater:trafficUpdater,
+ init:trafficInit,
+ name:"Uplink traffic map"
+};
+
+var handler_disco = {
+ updater:randomizeColors,
+ init:discoInit,
+ name:"Disco fever"
+};
+
+var handler_comment = {
+ updater:commentUpdater,
+ init:commentInit,
+ name:"Fresh comment spotter"
+};
+/*
+ * Update function for uplink map
+ * Run periodically when uplink map is active.
+ */
+function uplinkUpdater()
+{
+ if (!nms.switches_now["switches"])
+ return;
+ for (sw in nms.switches_now["switches"]) {
+ var uplinks=0;
+ for (port in nms.switches_now["switches"][sw]["ports"]) {
+ if (!nms.switches_then["switches"][sw]["ports"] ||
+ !nms.switches_now["switches"][sw]["ports"])
+ continue;
+ if (/ge-0\/0\/44$/.exec(port) ||
+ /ge-0\/0\/45$/.exec(port) ||
+ /ge-0\/0\/46$/.exec(port) ||
+ /ge-0\/0\/47$/.exec(port))
+ {
+ if (parseInt(nms.switches_then["switches"][sw]["ports"][port]["ifhcoutoctets"]) != parseInt(nms.switches_now["switches"][sw]["ports"][port]["ifhcoutoctets"])) {
+ uplinks += 1;
+ }
+ }
+ }
+ if (uplinks == 0) {
+ setSwitchColor(sw,"blue");
+ } else if (uplinks == 1) {
+ setSwitchColor(sw,"red");
+ } else if (uplinks == 2) {
+ setSwitchColor(sw, "yellow");
+ } else if (uplinks == 3) {
+ setSwitchColor(sw, "green");
+ } else if (uplinks > 3) {
+ setSwitchColor(sw, "white");
+ }
+ }
+}
+
+/*
+ * Init-function for uplink map
+ */
+function trafficInit()
+{
+ setLegend(1,"blue","0 (N/A)");
+ setLegend(5,"red", "1000Mb/s or more");
+ setLegend(4,"yellow","100Mb/s to 800Mb/s");
+ setLegend(3,"green", "5Mb/s to 100Mb/s");
+ setLegend(2,"white","0 to 5Mb/s");
+}
+
+function trafficUpdater()
+{
+ if (!nms.switches_now["switches"])
+ return;
+ for (sw in nms.switches_now["switches"]) {
+ var speed = 0;
+ for (port in nms.switches_now["switches"][sw]["ports"]) {
+ if (/ge-0\/0\/44$/.exec(port) ||
+ /ge-0\/0\/45$/.exec(port) ||
+ /ge-0\/0\/46$/.exec(port) ||
+ /ge-0\/0\/47$/.exec(port))
+ {
+ var t = nms.switches_then["switches"][sw]["ports"][port];
+ var n = nms.switches_now["switches"][sw]["ports"][port];
+ speed += (parseInt(t["ifhcoutoctets"]) -parseInt(n["ifhcoutoctets"])) / (parseInt(t["time"] - n["time"]));
+ speed += (parseInt(t["ifhcinoctets"]) -parseInt(n["ifhcinoctets"])) / (parseInt(t["time"] - n["time"]));
+ }
+ }
+ var m = 1024 * 1024 / 8;
+ if (speed == 0) {
+ setSwitchColor(sw,"blue");
+ } else if (speed > (1000 * m)) {
+ setSwitchColor(sw,"red");
+ } else if (speed > (800 * m)) {
+ setSwitchColor(sw, "yellow");
+ } else if (speed > (5 * m)) {
+ setSwitchColor(sw, "green");
+ } else {
+ setSwitchColor(sw, "white");
+ }
+ }
+}
+
+/*
+ * Init-function for uplink map
+ */
+function uplinkInit()
+{
+ setLegend(1,"blue","0 uplinks");
+ setLegend(2,"red","1 uplink");
+ setLegend(3,"yellow","2 uplinks");
+ setLegend(4,"green","3 uplinks");
+ setLegend(5,"white","4 uplinks");
+}
+
+
+/*
+ * Tweaked this to scale from roughly 20C to 35C. Hence the -20 and /15
+ * thing (e.g., "0" is 20 and "15" is 35 by the time we pass it to
+ * rgb_from_max());
+ */
+function temp_color(t)
+{
+ if (t == undefined) {
+ console.log("Temp_color, but temp is undefined");
+ return "blue";
+ }
+ t = parseInt(t) - 20;
+ t = Math.floor((t / 15) * 100);
+ return rgb_from_max(t);
+}
+
+function tempUpdater()
+{
+ for (sw in nms.switches_now["switches"]) {
+ var t = "white";
+ if (nms.switches_now["switches"][sw]["temp"]) {
+ t = temp_color(nms.switches_now["switches"][sw]["temp"]);
+ }
+
+ setSwitchColor(sw, t);
+ }
+}
+
+function tempInit()
+{
+ setLegend(1,temp_color(20),"20 °C");
+ setLegend(2,temp_color(22),"22 °C");
+ setLegend(3,temp_color(27),"27 °C");
+ setLegend(4,temp_color(31),"31 °C");
+ setLegend(5,temp_color(35),"35 °C");
+}
+
+function pingUpdater()
+{
+ for (var sw in nms.switches_now["switches"]) {
+ var c = "blue";
+ if (nms.ping_data['switches'] && nms.ping_data['switches'][sw])
+ c = gradient_from_latency(nms.ping_data["switches"][sw]["latency"]);
+ setSwitchColor(sw, c);
+ }
+ for (var ln in nms.switches_now["linknets"]) {
+ var c1 = "blue";
+ var c2 = c1;
+ if (nms.ping_data['linknets'] && nms.ping_data['linknets'][ln]) {
+ c1 = gradient_from_latency(nms.ping_data["linknets"][ln][0]);
+ c2 = gradient_from_latency(nms.ping_data["linknets"][ln][1]);
+ }
+ setLinknetColors(ln, c1, c2);
+ }
+}
+
+function pingInit()
+{
+ setLegend(1,gradient_from_latency(1),"1ms");
+ setLegend(2,gradient_from_latency(30),"30ms");
+ setLegend(3,gradient_from_latency(60),"60ms");
+ setLegend(4,gradient_from_latency(80),"80ms");
+ setLegend(5,"#0000ff" ,"No response");
+}
+
+function commentUpdater()
+{
+ var realnow = Date.now();
+ if (nms.now) {
+ realnow = Date.parse(nms.now);
+ }
+ var now = Math.floor(realnow / 1000);
+ for (var sw in nms.switches_now["switches"]) {
+ var c = "green";
+ var s = nms.switches_now["switches"][sw];
+ if (s["comments"] && s["comments"].length > 0) {
+ var then = 0;
+ c = "yellow";
+ for (var v in s["comments"]) {
+ var then_test = parseInt(s["comments"][v]["time"]);
+ if (then_test > then && then_test <= now)
+ then = then_test;
+ }
+ if (then > (now - (60*15))) {
+ c = "red";
+ } else if (then > (now - (120*60))) {
+ c = "orange";
+ } else if (then < (now - (60*60*24))) {
+ c = "white";
+ }
+ /*
+ * Special case during time travel: We have
+ * comments, but are not showing them yet.
+ */
+ if (then == 0)
+ c = "green";
+ }
+ setSwitchColor(sw, c);
+ }
+}
+
+function commentInit()
+{
+ setLegend(1,"green","0 comments");
+ setLegend(2,"white","1d+ old");
+ setLegend(3,"red", "0 - 15m old");
+ setLegend(4,"orange","15m - 120m old");
+ setLegend(5,"yellow" ,"2h - 24h old");
+}
+/*
+ * Testing-function to randomize colors of linknets and switches
+ */
+function randomizeColors()
+{
+ for (var i in nms.switches_now.linknets) {
+ setLinknetColors(i, getRandomColor(), getRandomColor());
+ }
+ for (var sw in nms.switches_now.switches) {
+ setSwitchColor(sw, getRandomColor());
+ }
+}
+
+function discoInit()
+{
+ setNightMode(true);
+ setLegend(1,"blue","Y");
+ setLegend(2,"red", "M");
+ setLegend(3,"yellow","C");
+ setLegend(4,"green", "A");
+ setLegend(5,"white","!");
+}
+
diff --git a/web/nms.gathering.org/nms2/js/nms.js b/web/nms.gathering.org/nms2/js/nms.js
index 97c0dc1..589f75e 100644
--- a/web/nms.gathering.org/nms2/js/nms.js
+++ b/web/nms.gathering.org/nms2/js/nms.js
@@ -3,7 +3,6 @@ var nms = {
switches_now:undefined, // Most recent data
switches_then:undefined, // 2 minutes old
speed:0, // Current aggregated speed
- full_speed:false, // Set to 'true' to include ALL interfaces
ping_data:undefined, // JSON data for ping history.
drawn:false, // Set to 'true' when switches are drawn
switch_showing:"", // Which switch we are displaying (if any).
@@ -18,8 +17,15 @@ var nms = {
linknet_color:{}, // color for linknet
textDrawn:{}, // Have we drawn text for this switch?
now:false, // Date we are looking at (false for current date).
- fontSize:14, // This is scaled too, but 14 seems to make sense.
+ fontSize:16, // This is scaled too, but 16 seems to make sense.
fontFace:"Arial Black",
+ /*
+ * This is used to track outbound AJAX requests and skip updates if
+ * we have too many outstanding requests. The ajaxOverflow is a
+ * counter that tracks how many times this has happened.
+ *
+ * It's a cheap way to be nice to the server.
+ */
outstandingAjaxRequests:0,
ajaxOverflow:0,
/*
@@ -29,12 +35,15 @@ var nms = {
*/
did_update:false,
/*
- * Various setInterval() handlers.
+ * Various setInterval() handlers. See nmsTimer() for how they are
+ * used.
+ *
+ * Cool fact: Adding one here adds it to the 'debug timers'
+ * drop-down.
*/
- handlers: {
+ timers: {
replay:false,
ports:false,
- info:false,
ping:false,
map:false,
speed:false
@@ -124,47 +133,22 @@ var margin = {
text:3
};
+/*
+ * All of these should be moved into nms.*
+ *
+ * tgStart/tgEnd are "constants".
+ * replayTime is the current time as far as the replay-function is. This
+ * should be merged with nms.now.
+ *
+ * replayIncrement is how many seconds to add for each replay timer tick
+ * (e.g.: 30 minutes added for every 1 second display-time).
+ */
var tgStart = stringToEpoch('2015-04-01T09:00:00');
var tgEnd = stringToEpoch('2015-04-05T12:00:00');
var replayTime = 0;
var replayIncrement = 30 * 60;
/*
- * Handlers. "updater" is run periodically when the handler is active, and
- * "init" is run once when it's activated.
- */
-
-var handler_uplinks = {
- updater:uplinkUpdater,
- init:uplinkInit,
- name:"Uplink map"
-};
-
-var handler_temp = {
- updater:tempUpdater,
- init:tempInit,
- name:"Temperature map"
-};
-
-var handler_ping = {
- updater:pingUpdater,
- init:pingInit,
- name:"IPv4 Ping map"
-};
-
-var handler_traffic = {
- updater:trafficUpdater,
- init:trafficInit,
- name:"Uplink traffic map"
-};
-
-var handler_disco = {
- updater:randomizeColors,
- init:discoInit,
- name:"Disco fever"
-};
-
-/*
* Convenience-function to populate the 'dr' structure.
*
* Only run once.
@@ -190,6 +174,10 @@ function initDrawing() {
dr['top']['ctx'] = dr['top']['c'].getContext('2d');
}
+/*
+ * Convenience function that doesn't support huge numbers, and it's easier
+ * to comment than to fix. But not really, but I'm not fixing it anyway.
+ */
function byteCount(bytes) {
var units = ['', 'K', 'M', 'G', 'T', 'P'];
i = 0;
@@ -200,11 +188,20 @@ function byteCount(bytes) {
return bytes.toFixed(1) + units[i];
}
+/*
+ * Definitely not a way to toggle night mode. Does something COMPLETELY
+ * DIFFERENT.
+ */
function toggleNightMode()
{
setNightMode(!nms.nightMode);
}
+/*
+ * Parse 'now' from user-input.
+ *
+ * Should probably just use stringToEpoch() instead, but alas, not yet.
+ */
function checkNow(now)
{
if (Date.parse(now)) {
@@ -219,41 +216,86 @@ function checkNow(now)
return false;
}
-
+/*
+ * Convert back and forth between epoch.
+ *
+ * There's no particular reason why I use seconds instead of javascript
+ * microseconds, except to leave the mark of a C coder on this javascript
+ * project.
+ */
function stringToEpoch(t)
{
var ret = new Date(Date.parse(t));
return parseInt(parseInt(ret.valueOf()) / 1000);
}
+/*
+ * Have to pad with zeroes to avoid "17:5:0" instead of the conventional
+ * and more readable "17:05:00". I'm sure there's a better way, but this
+ * works just fine.
+ */
function epochToString(t)
{
var d = new Date(parseInt(t) * parseInt(1000));
- var str = d.getFullYear() + "-" + (parseInt(d.getMonth())+1) + "-" + d.getDate() + "T";
- str += d.getHours() + ":" + d.getMinutes() + ":" + d.getSeconds();
+ var str = d.getFullYear() + "-";
+ if (parseInt(d.getMonth()) < 9)
+ str += "0";
+ str += (parseInt(d.getMonth())+1) + "-";
+ if (d.getDate() < 10)
+ str += "0";
+ str += d.getDate() + "T";
+ if (d.getHours() < 10)
+ str += "0";
+ str += d.getHours() + ":";
+ if (d.getMinutes() < 10)
+ str += "0";
+ str += d.getMinutes() + ":";
+ if (d.getSeconds() < 10)
+ str += "0";
+ str += d.getSeconds();
+
return str;
}
-
+/*
+ * Move 'nms.now' forward in time, unless we're at the end of the event.
+ *
+ * This is run on a timer (nms.timers.replay) every second when we are
+ * replaying.
+ */
function timeReplay()
{
if (replayTime >= tgEnd) {
- nms.handlers.replay.stop();
+ nms.timers.replay.stop();
return;
}
replayTime = parseInt(replayTime) + parseInt(replayIncrement);
nms.now = epochToString(replayTime);
- drawNow();
}
+/*
+ * Start replaying the event.
+ *
+ * I want this to be more generic:
+ * - Set time
+ * - Set end-time
+ * - Start/stop/pause
+ * - Set speed increment
+ *
+ * Once the lib supports this, I can move 'tgStart' and 'tgEnd' to the GUI
+ * and just provide them as default values or templates.
+ */
function startReplay() {
- nms.handlers.replay.stop();
+ nms.timers.replay.stop();
resetColors();
replayTime = tgStart;
timeReplay();
- nms.handlers.replay.start();;
+ nms.timers.replay.start();;
}
+/*
+ * Used to move to a specific time, but not replay.
+ */
function changeNow() {
var newnow = checkNow(document.getElementById("nowPicker").value);
if (!newnow) {
@@ -277,10 +319,15 @@ function changeNow() {
function hideSwitch()
{
var swtop = document.getElementById("info-switch-parent");
- var swpanel = document.getElementById("info-switch-panel-body");
var switchele = document.getElementById("info-switch-table");
+ var comments = document.getElementById("info-switch-comments-table");
if (switchele != undefined)
- swpanel.removeChild(switchele);
+ switchele.parentNode.removeChild(switchele);
+ if (comments != undefined)
+ comments.parentNode.removeChild(comments);
+ commentbox = document.getElementById("commentbox");
+ if (commentbox != undefined)
+ commentbox.parentNode.removeChild(commentbox);
swtop.style.display = 'none';
nms.switch_showing = "";
}
@@ -414,145 +461,44 @@ function switchInfo(x)
td2.innerHTML = sw["management"]["poll_frequency"];
tr.appendChild(td1); tr.appendChild(td2); switchele.appendChild(tr);
-
- swpanel.appendChild(switchele);
- swtop.style.display = 'block';
-}
-
-/*
- * Update various info elements periodically.
- */
-function updateInfo()
-{
- if (!nms.drawn && nms.switches_now != undefined) {
- drawSwitches();
- nms.drawn = true;
- }
- var speedele = document.getElementById("speed");
- speedele.innerHTML = (8 * parseInt(nms.speed) / 1024 / 1024 / 1024 ).toPrecision(5) + " Gbit/s";
-}
-
-/*
- * Update function for uplink map
- * Run periodically when uplink map is active.
- */
-function uplinkUpdater()
-{
- if (!nms.switches_now["switches"])
- return;
- for (sw in nms.switches_now["switches"]) {
- var uplinks=0;
- for (port in nms.switches_now["switches"][sw]["ports"]) {
- if (!nms.switches_then["switches"][sw]["ports"] ||
- !nms.switches_now["switches"][sw]["ports"])
- continue;
- if (/ge-0\/0\/44$/.exec(port) ||
- /ge-0\/0\/45$/.exec(port) ||
- /ge-0\/0\/46$/.exec(port) ||
- /ge-0\/0\/47$/.exec(port))
- {
- if (parseInt(nms.switches_then["switches"][sw]["ports"][port]["ifhcoutoctets"]) != parseInt(nms.switches_now["switches"][sw]["ports"][port]["ifhcoutoctets"])) {
- uplinks += 1;
- }
- }
- }
- if (uplinks == 0) {
- setSwitchColor(sw,"blue");
- } else if (uplinks == 1) {
- setSwitchColor(sw,"red");
- } else if (uplinks == 2) {
- setSwitchColor(sw, "yellow");
- } else if (uplinks == 3) {
- setSwitchColor(sw, "green");
- } else if (uplinks > 3) {
- setSwitchColor(sw, "white");
- }
- }
-}
-
-/*
- * Init-function for uplink map
- */
-function trafficInit()
-{
- setLegend(1,"blue","0 uplink utilization");
- setLegend(5,"red", "1000Mb/s or more uplink utilization");
- setLegend(4,"yellow","100Mb/s to 800Mb/s uplink utilization");
- setLegend(3,"green", "5Mb/s to 100Mb/s uplink utilization");
- setLegend(2,"white","0 to 5Mb/s uplink utilization");
-}
-
-function trafficUpdater()
-{
- if (!nms.switches_now["switches"])
- return;
- for (sw in nms.switches_now["switches"]) {
- var speed = 0;
- for (port in nms.switches_now["switches"][sw]["ports"]) {
- if (/ge-0\/0\/44$/.exec(port) ||
- /ge-0\/0\/45$/.exec(port) ||
- /ge-0\/0\/46$/.exec(port) ||
- /ge-0\/0\/47$/.exec(port))
- {
- var t = nms.switches_then["switches"][sw]["ports"][port];
- var n = nms.switches_now["switches"][sw]["ports"][port];
- speed += (parseInt(t["ifhcoutoctets"]) -parseInt(n["ifhcoutoctets"])) / (parseInt(t["time"] - n["time"]));
- speed += (parseInt(t["ifhcinoctets"]) -parseInt(n["ifhcinoctets"])) / (parseInt(t["time"] - n["time"]));
- }
+
+ comments = document.createElement("table");
+ comments.id = "info-switch-comments-table";
+ comments.border = "1";
+ comments.className = "table col-md-6";
+ var cap = document.createElement("caption");
+ cap.innerText = "Comments";
+ comments.appendChild(cap);
+
+ tr = document.createElement("tr"); td1 = document.createElement("th"); td2 = document.createElement("th");
+ td3 = document.createElement("th");
+ td1.innerText = "Time";
+ td2.innerText = "User";
+ td3.innerText = "Comment";
+ tr.appendChild(td1); tr.appendChild(td2); tr.appendChild(td3); comments.appendChild(tr);
+ var has_comment = false;
+ for (var c in sw["comments"]) {
+ var comment = sw["comments"][c];
+ has_comment = true;
+ if (comment["state"] == "active" || comment["state"] == "persist") {
+ tr = document.createElement("tr"); td1 = document.createElement("td"); td2 = document.createElement("td");
+ td3 = document.createElement("td");
+ td1.innerText = epochToString(comment["time"]) + " ";
+ td2.innerText = comment["username"] + " ";
+ td3.innerText = comment['comment'];
+ tr.appendChild(td1); tr.appendChild(td2); tr.appendChild(td3); comments.appendChild(tr);
+ }
}
- var m = 1024 * 1024 / 8;
- if (speed == 0) {
- setSwitchColor(sw,"blue");
- } else if (speed > (1000 * m)) {
- setSwitchColor(sw,"red");
- } else if (speed > (800 * m)) {
- setSwitchColor(sw, "yellow");
- } else if (speed > (5 * m)) {
- setSwitchColor(sw, "green");
- } else {
- setSwitchColor(sw, "white");
+
+ swpanel.appendChild(switchele);
+ if (has_comment) {
+ swpanel.appendChild(comments);
}
- }
-}
-
-/*
- * Init-function for uplink map
- */
-function uplinkInit()
-{
- setLegend(1,"blue","0 uplinks");
- setLegend(2,"red","1 uplink");
- setLegend(3,"yellow","2 uplinks");
- setLegend(4,"green","3 uplinks");
- setLegend(5,"white","4 uplinks");
-}
-
-/*
- * Give us a color from blue (0) to red (100).
- */
-function rgb_from_max(x)
-{
- x = x/100;
- var colorred = 255 * x;
- var colorblue = 255 - colorred;
-
- return 'rgb(' + Math.floor(colorred) + ", 0, " + Math.floor(colorblue) + ')';
-}
-
-/*
- * Tweaked this to scale from roughly 20C to 35C. Hence the -20 and /15
- * thing (e.g., "0" is 20 and "15" is 35 by the time we pass it to
- * rgb_from_max());
- */
-function temp_color(t)
-{
- if (t == undefined) {
- console.log("Temp_color, but temp is undefined");
- return "blue";
- }
- t = parseInt(t) - 20;
- t = Math.floor((t / 15) * 100);
- return rgb_from_max(t);
+ var commentbox = document.createElement("div");
+ commentbox.id = "commentbox";
+ commentbox.innerHTML = '<input type="text" placeholder="Comment" id="' + x + '-comment"><button onclick="addComment(\'' + x + '\',document.getElementById(\'' + x + '-comment\').value); document.getElementById(\'' + x + '-comment\').value = \'added. Wait for it....\';">Add comment</button>';
+ swpanel.appendChild(commentbox);
+ swtop.style.display = 'block';
}
/*
@@ -569,86 +515,6 @@ function setLegend(x,color,name)
el.innerHTML = name;
}
-function tempUpdater()
-{
- for (sw in nms.switches_now["switches"]) {
- var t = "white";
- if (nms.switches_now["switches"][sw]["temp"]) {
- t = temp_color(nms.switches_now["switches"][sw]["temp"]);
- }
-
- setSwitchColor(sw, t);
- }
-}
-
-function tempInit()
-{
- setLegend(1,temp_color(20),"20 °C");
- setLegend(2,temp_color(22),"22 °C");
- setLegend(3,temp_color(27),"27 °C");
- setLegend(4,temp_color(31),"31 °C");
- setLegend(5,temp_color(35),"35 °C");
-}
-
-function gradient_from_latency(latency_ms, latency_secondary_ms)
-{
- if (latency_secondary_ms === undefined) {
- return rgb_from_latency(latency_ms);
- }
- return 'linear-gradient(' +
- rgb_from_latency(latency_ms) + ', ' +
- rgb_from_latency(latency_secondary_ms) + ')';
-}
-
-function rgb_from_latency(latency_ms)
-{
- if (latency_ms === null || latency_ms === undefined) {
- return '#0000ff';
- }
-
- var l = latency_ms / 40.0;
- if (l >= 2.0) {
- return 'rgb(255, 0, 0)';
- } else if (l >= 1.0) {
- l = 2.0 - l;
- l = Math.pow(l, 1.0/2.2);
- l = Math.floor(l * 255.0);
- return 'rgb(255, ' + l + ', 0)';
- } else {
- l = Math.pow(l, 1.0/2.2);
- l = Math.floor(l * 255.0);
- return 'rgb(' + l + ', 255, 0)';
- }
-}
-
-function pingUpdater()
-{
- for (var sw in nms.switches_now["switches"]) {
- var c = "blue";
- if (nms.ping_data['switches'] && nms.ping_data['switches'][sw])
- c = gradient_from_latency(nms.ping_data["switches"][sw]["latency"]);
- setSwitchColor(sw, c);
- }
- for (var ln in nms.switches_now["linknets"]) {
- var c1 = "blue";
- var c2 = c1;
- if (nms.ping_data['linknets'] && nms.ping_data['linknets'][ln]) {
- c1 = gradient_from_latency(nms.ping_data["linknets"][ln][0]);
- c2 = gradient_from_latency(nms.ping_data["linknets"][ln][1]);
- }
- setLinknetColors(ln, c1, c2);
- }
-}
-
-function pingInit()
-{
- setLegend(1,gradient_from_latency(1),"1ms");
- setLegend(2,gradient_from_latency(30),"30ms");
- setLegend(3,gradient_from_latency(60),"60ms");
- setLegend(4,gradient_from_latency(80),"80ms");
- setLegend(5,"#0000ff" ,"No response");
-}
-
/*
* Run periodically to trigger map updates when a handler is active
*/
@@ -657,6 +523,7 @@ function updateMap()
if (nms.updater != undefined && nms.switches_now && nms.switches_then) {
nms.updater();
}
+ drawNow();
}
/*
@@ -719,6 +586,18 @@ function updatePing()
});
}
+function addComment(sw,comment) {
+ var myData = {
+ switch:sw,
+ comment:comment};
+ console.log(myData);
+ $.ajax({
+ type: "POST",
+ url: "/switch-comment.pl",
+ dataType: "text",
+ data:myData
+ });
+}
/*
* Update nms.switches_now and nms.switches_then
*/
@@ -768,18 +647,24 @@ function updatePorts()
/*
* Use nms.switches_now and nms.switches_then to update 'nms.speed'.
*
- * nms.speed is a total of ifHCInOctets across all interfaces.
+ * nms.speed is a total of ifHCInOctets across all client-interfaces
+ * nms.speed_full is a total of for /all/ interfaces.
+ *
+ * This is run separate of updatePorts mainly for historic reasons, but
+ * if it was added to the tail end of updatePorts, there'd have to be some
+ * logic to ensure it was run after both requests. Right now, it's just
+ * equally wrong for both scenarios, not consistently wrong (or something).
+ *
+ * FIXME: Err, yeah, add this to the tail-end of updatePorts instead :D
*
- * if nms.full_speed is true: Include ALL interfaces
- * if nms.full_speed is false: Include only e* switches and exclude
- * uplinks.
*/
function updateSpeed()
{
var speed_in = parseInt(0);
- var speed_kant = parseInt(0);
+ var speed_full = parseInt(0);
var counter=0;
var sw;
+ var speedele = document.getElementById("speed");
for (sw in nms.switches_now["switches"]) {
for (port in nms.switches_now["switches"][sw]["ports"]) {
if (!nms.switches_now["switches"][sw]["ports"][port]) {
@@ -804,8 +689,9 @@ function updateSpeed()
if (then == 0 || now == 0 || diffval == 0 || diffval == NaN) {
continue;
}
- if (nms.full_speed || (( /e\d-\d/.exec(sw) || /e\d\d-\d/.exec(sw)) && ( /ge-\d\/\d\/\d$/.exec(port) || /ge-\d\/\d\/\d\d$/.exec(port)))) {
- if (nms.full_speed || !(
+ speed_full += parseInt(diffval/diff);
+ if (( /e\d-\d/.exec(sw) || /e\d\d-\d/.exec(sw)) && ( /ge-\d\/\d\/\d$/.exec(port) || /ge-\d\/\d\/\d\d$/.exec(port))) {
+ if (!(
/ge-0\/0\/44$/.exec(port) ||
/ge-0\/0\/45$/.exec(port) ||
/ge-0\/0\/46$/.exec(port) ||
@@ -814,10 +700,15 @@ function updateSpeed()
counter++;
}
}
- //speed_in += parseInt(diffval/diff) / 1024 ;
}
}
nms.speed = speed_in;
+ nms.speed_full = speed_full;
+ if (speedele) {
+ speedele.innerHTML = byteCount(8 * parseInt(nms.speed)) + "bit/s";
+ speedele.innerHTML += " / " + byteCount(8 * parseInt(nms.speed_full)) + "bit/s";
+
+ }
}
/*
@@ -929,21 +820,24 @@ function drawSwitches()
/*
* Draw current time-window
+ *
+ * FIXME: The math here is just wild approximation and guesswork because
+ * I'm lazy.
*/
function drawNow()
{
- if (nms.now != false) {
- dr.top.ctx.font = Math.round(2 * nms.fontSize * canvas.scale) + "px " + nms.fontFace;
- dr.top.ctx.clearRect(0,0,Math.floor(400 * canvas.scale),Math.floor(60 * canvas.scale));
- dr.top.ctx.fillStyle = "white";
- dr.top.ctx.strokeStyle = "black";
- dr.top.ctx.lineWidth = Math.round(2 * canvas.scale);
- if (canvas.scale < 0.7) {
- dr.top.ctx.lineWidth = 2;
- }
- dr.top.ctx.strokeText("Now: " + nms.now, 0 + margin.text, 30 * canvas.scale);
- dr.top.ctx.fillText("Now: " + nms.now, 0 + margin.text, 30 * canvas.scale);
+ // XXX: Get rid of microseconds that we get from the backend.
+ var now = /^[^.]*/.exec(nms.switches_now.time);
+ dr.top.ctx.font = Math.round(2 * nms.fontSize * canvas.scale) + "px " + nms.fontFace;
+ dr.top.ctx.clearRect(0,0,Math.floor(800 * canvas.scale),Math.floor(100 * canvas.scale));
+ dr.top.ctx.fillStyle = "white";
+ dr.top.ctx.strokeStyle = "black";
+ dr.top.ctx.lineWidth = Math.floor(4 * canvas.scale);
+ if (dr.top.ctx.lineWidth == 0) {
+ dr.top.ctx.lineWidth = Math.round(4 * canvas.scale);
}
+ dr.top.ctx.strokeText(now, 0 + margin.text, 30 * canvas.scale);
+ dr.top.ctx.fillText(now, 0 + margin.text, 30 * canvas.scale);
}
/*
* Draw foreground/scene.
@@ -1025,16 +919,6 @@ function setSwitchColor(sw, c)
}
/*
- * Return a random-ish color (for testing)
- */
-function getRandomColor()
-{
- var i = Math.round(Math.random() * 5);
- var colors = [ "white", "red", "pink", "yellow", "orange", "green" ];
- return colors[i];
-}
-
-/*
* Event handler for the front-end drag bar to change scale
*/
function scaleChange()
@@ -1053,29 +937,6 @@ function switchClick(sw)
}
/*
- * Testing-function to randomize colors of linknets and switches
- */
-function randomizeColors()
-{
- for (var i in nms.switches_now.linknets) {
- setLinknetColors(i, getRandomColor(), getRandomColor());
- }
- for (var sw in nms.switches_now.switches) {
- setSwitchColor(sw, getRandomColor());
- }
-}
-
-function discoInit()
-{
- setNightMode(true);
- setLegend(1,"blue","0");
- setLegend(5,"red", "1");
- setLegend(4,"yellow","2");
- setLegend(3,"green", "3");
- setLegend(2,"white","4");
-}
-
-/*
* Resets the colors of linknets and switches.
*
* Useful when mode changes so we don't re-use colors from previous modes
@@ -1182,9 +1043,9 @@ function drawSideways(text,x,y,w,h)
dr.text.ctx.rotate(Math.PI * 3 / 2);
dr.text.ctx.fillStyle = "white";
dr.text.ctx.strokeStyle = "black";
- dr.text.ctx.lineWidth = Math.floor(1 * canvas.scale);
- if (canvas.scale < 0.7) {
- dr.text.ctx.lineWidth = 0.5;
+ dr.text.ctx.lineWidth = Math.floor(3 * canvas.scale);
+ if (dr.text.ctx.lineWidth == 0) {
+ dr.text.ctx.lineWidth = Math.round(3 * canvas.scale);
}
dr.text.ctx.strokeText(text, - canvas.scale * (y + h - margin.text),canvas.scale * (x + w - margin.text) );
dr.text.ctx.fillText(text, - canvas.scale * (y + h - margin.text),canvas.scale * (x + w - margin.text) );
@@ -1224,9 +1085,9 @@ function drawRegular(text,x,y,w,h) {
dr.text.ctx.fillStyle = "white";
dr.text.ctx.strokeStyle = "black";
- dr.text.ctx.lineWidth = Math.floor(1 * canvas.scale);
- if (canvas.scale < 0.7) {
- dr.text.ctx.lineWidth = 0.5;
+ dr.text.ctx.lineWidth = Math.floor(3 * canvas.scale);
+ if (dr.text.ctx.lineWidth == 0) {
+ dr.text.ctx.lineWidth = Math.round(3 * canvas.scale);
}
dr.text.ctx.strokeText(text, (x + margin.text) * canvas.scale, (y + h - margin.text) * canvas.scale);
dr.text.ctx.fillText(text, (x + margin.text) * canvas.scale, (y + h - margin.text) * canvas.scale);
@@ -1263,33 +1124,38 @@ function connectSwitches(insw1, insw2,color1, color2) {
dr.link.ctx.moveTo(0,0);
}
-
+/*
+ * Boot up "fully fledged" NMS.
+ *
+ * If you only want parts of the functionality, then re-implement this
+ * (e.g., just add and start the handlers you want, don't worry about
+ * drawing, etc).
+ */
function initNMS() {
- var url;
initDrawing();
updatePorts();
updatePing();
window.addEventListener('resize',resizeEvent,true);
document.addEventListener('load',resizeEvent,true);
- nms.handlers.ports = new nmsTimer(updatePorts, 1000, "Port updater", "AJAX request to update port data (traffic, etc)");
- nms.handlers.ports.start();
-
- nms.handlers.info = new nmsTimer(updateInfo, 5000, "Info updater", "Updates info-box about client speed (fast - no backend requests)");
- nms.handlers.info.start();
+ nms.timers.ports = new nmsTimer(updatePorts, 1000, "Port updater", "AJAX request to update port data (traffic, etc)");
+ nms.timers.ports.start();
- nms.handlers.ping = new nmsTimer(updatePing, 1000, "Ping updater", "AJAX request to update ping data");
- nms.handlers.ping.start();
+ nms.timers.ping = new nmsTimer(updatePing, 1000, "Ping updater", "AJAX request to update ping data");
+ nms.timers.ping.start();
- nms.handlers.map = new nmsTimer(updateMap, 1000, "Map handler", "Updates the map using the chosen map handler (ping, uplink, traffic, etc)");
- nms.handlers.map.start();
+ nms.timers.map = new nmsTimer(updateMap, 1000, "Map handler", "Updates the map using the chosen map handler (ping, uplink, traffic, etc)");
+ nms.timers.map.start();
- nms.handlers.speed = new nmsTimer(updateSpeed, 3000, "Speed updater", "Recompute total speed (no backend requests)");
- nms.handlers.speed.start();
+ nms.timers.speed = new nmsTimer(updateSpeed, 1000, "Speed updater", "Recompute total speed (no backend requests)");
+ nms.timers.speed.start();
- nms.handlers.replay = new nmsTimer(timeReplay, 1000, "Time machine", "Handler used to change time");
+ nms.timers.replay = new nmsTimer(timeReplay, 1000, "Time machine", "Handler used to change time");
+ detectHandler();
+}
- url = document.URL;
+function detectHandler() {
+ var url = document.URL;
if (/#ping/.exec(url)) {
setUpdater(handler_ping);
}else if (/#uplink/.exec(url)) {
@@ -1298,6 +1164,8 @@ function initNMS() {
setUpdater(handler_temp);
} else if (/#traffic/.exec(url)) {
setUpdater(handler_traffic);
+ } else if (/#comment/.exec(url)) {
+ setUpdater(handler_comment);
} else if (/#disco/.exec(url)) {
setUpdater(handler_disco);
} else {
@@ -1308,6 +1176,11 @@ function initNMS() {
}
}
+/*
+ * Display and populate the dialog box for debugging timers.
+ *
+ * Could probably be cleaned up.
+ */
function showTimerDebug() {
var tableTop = document.getElementById('timerTableTop');
var table = document.getElementById('timerTable');
@@ -1321,43 +1194,38 @@ function showTimerDebug() {
table.classList.add("table");
table.classList.add("table-default");
table.border = "1";
- tr = document.createElement("tr");
- td = document.createElement("th");
- td.innerHTML = "Handler";
- tr.appendChild(td);
- td = document.createElement("th");
- td.innerHTML = "Interval (ms)";
- tr.appendChild(td);
- td = document.createElement("th");
- td.innerHTML = "Name";
- tr.appendChild(td);
- td = document.createElement("th");
- td.innerHTML = "Description";
- tr.appendChild(td);
- table.appendChild(tr);
- for (var v in nms.handlers) {
+ tr = document.createElement("tr");
+ td = document.createElement("th");
+ td.innerHTML = "Handler";
+ tr.appendChild(td);
+ td = document.createElement("th");
+ td.innerHTML = "Interval (ms)";
+ tr.appendChild(td);
+ td = document.createElement("th");
+ td.innerHTML = "Name";
+ tr.appendChild(td);
+ td = document.createElement("th");
+ td.innerHTML = "Description";
+ tr.appendChild(td);
+ table.appendChild(tr);
+ for (var v in nms.timers) {
+ console.log(v);
tr = document.createElement("tr");
td = document.createElement("td");
- td.innerHTML = nms.handlers[v].handle;
+ td.innerHTML = nms.timers[v].handle;
tr.appendChild(td);
td = document.createElement("td");
- td.innerHTML = "<input type=\"text\" id='handlerValue" + v + "' value='" + nms.handlers[v].interval + "'>";
- td.innerHTML += "<button type=\"button\" class=\"btn btn-default\" onclick=\"nms.handlers['" + v + "'].setInterval(document.getElementById('handlerValue" + v + "').value);\">Apply</button>";
+ td.innerHTML = "<input type=\"text\" id='handlerValue" + v + "' value='" + nms.timers[v].interval + "'>";
+ td.innerHTML += "<button type=\"button\" class=\"btn btn-default\" onclick=\"nms.timers['" + v + "'].setInterval(document.getElementById('handlerValue" + v + "').value);\">Apply</button>";
tr.appendChild(td);
td = document.createElement("td");
- td.innerHTML = nms.handlers[v].name;
+ td.innerHTML = nms.timers[v].name;
tr.appendChild(td);
td = document.createElement("td");
- td.innerHTML = nms.handlers[v].description;
+ td.innerHTML = nms.timers[v].description;
tr.appendChild(td);
table.appendChild(tr);
}
tableTop.appendChild(table);
document.getElementById('debugTimers').style.display = 'block';
}
-
-function debugHandlers() {
- for (var v in nms.handlers) {
- console.log(nms.handlers[v]);
- }
-}
diff --git a/web/nms.gathering.org/ping-json2.pl b/web/nms.gathering.org/ping-json2.pl
index e46140a..2ffe650 100755
--- a/web/nms.gathering.org/ping-json2.pl
+++ b/web/nms.gathering.org/ping-json2.pl
@@ -16,7 +16,7 @@ my $when =" updated > " . $now . " - '15 secs'::interval and updated < " . $now
my %json = ();
-my $q = $dbh->prepare("SELECT DISTINCT ON (updated, sysname) updated,sysname, latency_ms FROM ping NATURAL JOIN switches WHERE $when ORDER BY updated DESC;");
+my $q = $dbh->prepare("SELECT DISTINCT ON (sysname) updated,sysname, latency_ms FROM ping NATURAL JOIN switches WHERE updated in (select max(updated) from ping where $when group by switch)");
$q->execute();
while (my $ref = $q->fetchrow_hashref()) {
$json{'switches'}{$ref->{'sysname'}}{'latency'} = $ref->{'latency_ms'};
diff --git a/web/nms.gathering.org/port-state.pl b/web/nms.gathering.org/port-state.pl
index 76dd7d8..83e15f1 100755
--- a/web/nms.gathering.org/port-state.pl
+++ b/web/nms.gathering.org/port-state.pl
@@ -21,7 +21,7 @@ my $when =" time > " . $now . " - '5m'::interval and time < " . $now . " ";
my %json = ();
if (defined($cin)) {
- $when = " time < " . $now . " - '$cin'::interval and time > ". $now . " - ('$cin'::interval + '15m'::interval) ";
+ $when = " time < " . $now . " - '$cin'::interval and time > ". $now . " - ('$cin'::interval + '5m'::interval) ";
}
my $query = 'select sysname,extract(epoch from date_trunc(\'second\',time)) as time, ifname,ifhighspeed,ifhcinoctets,ifhcoutoctets from polls natural join switches where time in (select max(time) from polls where ' . $when . ' group by switch,ifname);';
@@ -37,7 +37,7 @@ while (my $ref = $q->fetchrow_hashref()) {
}
#print Dumper(%json);
-my $q2 = $dbh->prepare('select switch,sysname,placement,zorder,ip,switchtype,poll_frequency,community,last_updated from switches natural join placements');
+my $q2 = $dbh->prepare('select switch,sysname,placement,ip,switchtype,poll_frequency,community,last_updated from switches natural join placements');
my $q3 = $dbh->prepare('select distinct on (switch) switch,temp,time,sysname from switch_temp natural join switches where ' . $when . ' order by switch,time desc');
$q2->execute();
@@ -54,7 +54,6 @@ while (my $ref = $q2->fetchrow_hashref()) {
$json{'switches'}{$ref->{'sysname'}}{'placement'}{'y'} = $y2;
$json{'switches'}{$ref->{'sysname'}}{'placement'}{'width'} = $x1 - $x2;
$json{'switches'}{$ref->{'sysname'}}{'placement'}{'height'} = $y1 - $y2;
- $json{'switches'}{$ref->{'sysname'}}{'placement'}{'zorder'} = $ref->{'zorder'};
}
$q3->execute();
while (my $ref = $q3->fetchrow_hashref()) {
@@ -70,5 +69,16 @@ while (my $ref = $q4->fetchrow_hashref()) {
# push @{$json{'linknets'}}, $ref;
}
+my $q5 = $dbh->prepare ('select ' . $now . ' as time;');
+$q5->execute();
+$json{'time'} = $q5->fetchrow_hashref()->{'time'};
+
+my $q6 = $dbh->prepare('select sysname,extract(epoch from date_trunc(\'second\',time)) as time,state,username,id,comment from switch_comments natural join switches order by time desc');
+$q6->execute();
+while (my $ref = $q6->fetchrow_hashref()) {
+ push @{$json{'switches'}{$ref->{'sysname'}}{'comments'}},$ref;
+}
+
+$json{'username'} = $cgi->remote_user();
print $cgi->header(-type=>'text/json; charset=utf-8');
print JSON::XS::encode_json(\%json);
diff --git a/web/nms.gathering.org/switch-comment.pl b/web/nms.gathering.org/switch-comment.pl
new file mode 100755
index 0000000..262d625
--- /dev/null
+++ b/web/nms.gathering.org/switch-comment.pl
@@ -0,0 +1,25 @@
+#! /usr/bin/perl
+use CGI qw(fatalsToBrowser);
+use DBI;
+use lib '../../include';
+use utf8;
+use nms;
+use strict;
+use warnings;
+use Data::Dumper;
+
+my $cgi = CGI->new;
+
+my $dbh = nms::db_connect();
+
+my $data = $dbh->quote($cgi->param('comment') || die );
+my $switch = $dbh->quote($cgi->param('switch') || die );
+my $user = $dbh->quote($cgi->remote_user() || "undefined");
+
+
+my $q = $dbh->prepare("INSERT INTO switch_comments (time,username,switch,comment) values (now(),$user,(select switch from switches where sysname = $switch limit 1),$data)");
+$q->execute();
+
+print $cgi->header(-type=>'text/json; charset=utf-8');
+print "{ 'state': 'ok' }";
+