/** * Global variables */ // Save grid summary data, update every one minute var gridData; // Save nodes path, used for getting detail from rrd file var nodePath = new Object(); // Save nodes current status, // unknown = -2, error = -1, warning = 0 ,normal = 1 are used for sorting var nodeStatus = new Object(); // Update timer var gangliaTimer; // Global frame hash var framehash; // Global cec hash var cechash; // Global blade hash var bladehash; // Global x rack hash var rackhash; // Global other type node hash var otherhash; /** * Load Ganglia monitoring tool * * @return Nothing */ function loadGangliaMon() { $('#gangliamon').append(createInfoBar('Checking RPMs')); // Get groups and set cookie if (!$.cookie('groups')) { $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'extnoderange', tgt : '/.*', args : 'subgroups', msg : '' }, success : setGroupsCookies }); } // Check whether Ganglia RPMs are installed on the xCAT MN $.ajax({ url : 'lib/systemcmd.php', dataType : 'json', data : { cmd : 'rpm -q rrdtool ganglia-gmetad ganglia-gmond' }, success : checkGangliaRPMs }); return; } /** * Check whether Ganglia RPMs are installed * * @param data * Data returned from HTTP request * @return Nothing */ function checkGangliaRPMs(data) { var gangliaTab = $('#gangliamon'); gangliaTab.empty(); // Get the list of Ganglia RPMs installed var status = data.rsp.split(/\n/); var gangliaRPMs = ["rrdtool", "ganglia-gmetad", "ganglia-gmond"]; var warningMsg = 'Before continuing, please install the following packages: '; var missingRPMs = false; for (var i in status) { if (status[i].indexOf("not installed") > -1) { warningMsg += gangliaRPMs[i] + ' '; missingRPMs = true; } } // Append Ganglia PDF if (missingRPMs) { var warningBar = createWarnBar(warningMsg); warningBar.css('margin-bottom', '10px'); warningBar.prependTo(gangliaTab); } else { gangliaTab.append(createInfoBar('Checking running status')); // Check if ganglia is running on the xCAT MN $.ajax( { url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'monls', tgt : '', args : 'gangliamon', msg : '' }, success : checkGangliaRunning }); } return; } /** * Check whether Ganglia is running * * @param data * Data returned from HTTP request * @return Nothing */ function checkGangliaRunning(data) { var gangliaTab = $('#gangliamon'); gangliaTab.empty(); // If Ganglia is not started if (data.rsp[0].indexOf("not-monitored") > -1) { // Create link to start Ganglia var startLnk = $('Click here'); startLnk.css({ 'color' : 'blue', 'text-decoration' : 'none' }); startLnk.click(function() { // Turn on Ganglia for all nodes monitorNode('', 'on'); }); // Create warning bar var warningBar = $('
'); var msg = $('

').css({ 'display': 'inline-block', 'width': '90%' }); var icon = $('').css({ 'display': 'inline-block', 'margin': '10px 5px' }); warningBar.append(icon); msg.append('Please start Ganglia on xCAT. '); msg.append(startLnk); msg.append(' to start Ganglia.'); warningBar.append(msg); warningBar.css('margin-bottom', '10px'); // If there are any warning messages, append this warning after it var curWarnings = $('#gangliamon').find('.ui-state-error'); if (curWarnings.length) { curWarnings.after(warningBar); } else { warningBar.prependTo(gangliaTab); } return; } // Legend for node status var legend = '' + '' + '' + '' + '' + '
Normal Heavy Load Error Unknown
'; // Gganglia grid overview var showStr = '

Grid Overview

' + '[Hide]

' + '
' + '

Current Nodes Status

' + legend + '

' + '
All Nodes
' + '
'; gangliaTab.append(showStr); // Get summary data and draw on page $('#gangliaGridSummary').append('Getting grid summary data '); sendGridSummaryAjax(); // Get all nodes location data which can support the zoom monitor $('#gangliaNodes').append('Getting all nodes status '); sendLocationAjax(); // Bind the hide/show button event $('#gangliamon #hidesup').bind('click', function(){ if ('[Hide]' == $(this).text()) { $(this).html('[Show]'); } else { $(this).html('[Hide]'); } $('#gangliaGridSummary').toggle(); }); } /** * Send AJAX request to get all nodes parent and position to create hardware hierarchy hash * * @return Nothing */ function sendLocationAjax() { $.ajax({ url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'webrun', tgt : '', args : 'graph', msg : '' }, success: function(data){ if (!data.rsp[0]) { return; } extractLocationlData(data.rsp[0]); // Get nodes current status and draw on the page sendNodeCurrentAjax(); // Start the timer to update page per minute gangliaTimer = window.setTimeout('updateGangliaPage()', 60000); } }); } /** * Extract the location query data and saved in global variable * * @return Nothing */ function extractLocationlData(locationData) { framehash = new Object(); cechash = new Object(); bladehash = new Object(); rackhash = new Object(); // Linux nodes which has no parent linuxArray = new Array(); // Other unknown nodes only have one parent, use number 1 as there parent otherhash = new Object(); otherhash[1] = new Array(); var allnodearray = locationData.split(';'); var temparray; var parent = ''; var name = ''; for (var i in allnodearray) { temparray = allnodearray[i].split(':'); name = temparray[0]; // If there is not parent (or mpa, or rack) information parent = temparray[2]; if (!parent) { // Go to next node otherhash[1].push(name); continue; } switch (temparray[1].toLowerCase()) { case 'blade': { if (!bladehash[parent]) { bladehash[parent] = new Array(); } bladehash[parent].push(name); } break; case 'systemx': { if (!rackhash[parent]) { rackhash[parent] = new Array(); } rackhash[parent].push(name); } break; case 'frame': { if (!framehash[name]) { framehash[name] = new Array(); } } break; case 'cec': { if (!framehash[parent]) { framehash[parent] = new Array(); } framehash[parent].push(name); } break; case 'lpar': case 'lpar,osi': case 'osi,lpar': { if (!cechash[parent]) { cechash[parent] = new Array(); } cechash[parent].push(name); } break; default: { otherhash[1].push(name); } break; } } } /** * Send AJAX request to get grid summary information * * @return Nothing */ function sendGridSummaryAjax() { // Get the summary data $.ajax({ url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'webrun', tgt : '', args : 'gangliashow;_grid_;hour;_summary_', msg : '' }, success: function(data) { createGridSummaryData(data.rsp[0]); drawGridSummary(); } }); } /** * Send AJAX request to get nodes current load information * * @return Nothing */ function sendNodeCurrentAjax() { // Get all nodes current status $.ajax({ url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'webrun', tgt : '', args : 'gangliacurrent;node;', msg : '' }, success: function(data){ createNodeStatusData(data.rsp[0]); drawGangliaNodesArea($('#gangliaorder').val()); } }); } /** * Send AJAX request to get grid current summary information to update the page * * @return Nothing */ function sendGridCurrentAjax(){ // Get the summary data $.ajax({ url : 'lib/cmd.php', dataType : 'json', data : { cmd : 'webrun', tgt : '', args : 'gangliacurrent;grid', msg : '' }, success: function(data){ updateGridSummaryData(data.rsp[0]); drawGridSummary(); } }); } /** * Save the grid summary data to local global variable * * @param data structure * metric1:time11,val11,time12,val12....;metric2:time21,val21,time22,val22,...;.... * @return Nothing */ function createGridSummaryData(summaryString){ // Empty the global data gridData = new Object(); var metricArray = summaryString.split(';'); var metricname = ''; var valueArray = ''; var position = 0; var tempLength = 0; for (var index = 0; index < metricArray.length; index++) { position = metricArray[index].indexOf(':'); // Get the metric name and init its global array to save timestamp and value pair metricname = metricArray[index].substr(0, position); gridData[metricname] = new Array(); valueArray = metricArray[index].substr(position + 1).split(','); tempLength = valueArray.length; // Save timestamp and value into global array for (var i = 0; i < tempLength; i++) { gridData[metricname].push(Number(valueArray[i])); } } } /** * Update the grid summary data to local global variable * * @param data structure * metric1:time11,val11;metric2:time21,val21,time22;.... * @return Nothing */ function updateGridSummaryData(currentString){ var metricArray = currentString.split(';'); var metricname = ''; var position = 0; var tempLength = 0; var index = 0; var tempArray; tempLength = metricArray.length; for (index = 0; index < tempLength; index++) { position = metricArray[index].indexOf(':'); metricname = metricArray[index].substr(0, position); tempArray = metricArray[index].substr(position + 1).split(','); if (gridData[metricname]) { gridData[metricname].shift(); gridData[metricname].shift(); gridData[metricname].push(Number(tempArray[0])); gridData[metricname].push(Number(tempArray[1])); } } } /** * Draw the grid summay area by global data * * @return Nothing */ function drawGridSummary() { var gridDrawArea = $('#gangliaGridSummary'); var showStr = ''; var tempStr = $('#gangliamon').attr('class'); // jqflot only draws on the visible area // If the tab is hide, return directly if (tempStr.indexOf('hide') != -1) { return; } if ($('#gangliamon #hidesup').text() == '[Show]') { return; } gridDrawArea.empty(); showStr = '' + '' + '' + '' + '' + '
'; gridDrawArea.append(showStr); drawLoadFlot('gangliasummaryload', 'Grid', gridData['load_one'], gridData['cpu_num']); drawCpuFlot('gangliasummarycpu', 'Grid', gridData['cpu_idle']); drawMemFlot('gangliasummarymem', 'Grid', gridData['mem_free'], gridData['mem_total']); drawDiskFlot('gangliasummarydisk', 'Grid', gridData['disk_free'], gridData['disk_total']); drawNetworkFlot('gangliasummarynetwork', 'Grid', gridData['bytes_in'], gridData['bytes_out']); } /** * Draw the load flot by data(summary data, or one node's data) * * @param areaid * Which DIV draw this flot * @param loadpair * The load timestamp and value pair * @param cpupair * The CPU number and value pair * @return Nothing */ function drawLoadFlot(areaid, titleprefix, loadpair, cpupair) { var load = new Array(); var cpunum = new Array(); var index = 0; var yaxismax = 0; var interval = 1; $('#' + areaid).empty(); // Parse load pair, the timestamp must mutiply 1000, javascript time stamp is millisecond for (index = 0; index < loadpair.length; index += 2) { load.push([loadpair[index] * 1000, loadpair[index + 1]]); if (loadpair[index + 1] > yaxismax) { yaxismax = loadpair[index + 1]; } } // Parse cpu pair for (index = 0; index < cpupair.length; index += 2) { cpunum.push([cpupair[index] * 1000, cpupair[index + 1]]); if (cpupair[index + 1] > yaxismax) { yaxismax = cpupair[index + 1]; } } interval = parseInt(yaxismax / 3); if (interval < 1) { interval = 1; } $.jqplot(areaid, [load, cpunum], { title: titleprefix + ' Loads/Procs Last Hour', axes:{ xaxis:{ renderer : $.jqplot.DateAxisRenderer, numberTicks: 4, tickOptions : { formatString : '%R', show : true } }, yaxis: { min : 0, tickInterval : interval } }, legend : { show: true, location: 'nw' }, series:[{label:'Load'}, {label: 'CPU Number'}], seriesDefaults : {showMarker: false} }); } /** * Draw the CPU usage flot by data(maybe summary data, or one node's data) * * @param areaid * Which DIV draw this flot * @param titleprefix * Title used name * @param cpupair * The CPU timestamp and value pair * @return Nothing */ function drawCpuFlot(areaid, titleprefix, cpupair) { var cpu = new Array(); var index = 0; $('#' + areaid).empty(); // Time stamp should be mutiplied by 1000 // We get the CPU idle from server for (index = 0; index < cpupair.length; index +=2) { cpu.push([(cpupair[index] * 1000), (100 - cpupair[index + 1])]); } $.jqplot(areaid, [cpu],{ title: titleprefix + ' Cpu Use Last Hour', axes:{ xaxis:{ renderer : $.jqplot.DateAxisRenderer, numberTicks: 4, tickOptions : { formatString : '%R', show : true } }, yaxis: { min : 0, max : 100, tickOptions:{formatString : '%d\%'} } }, seriesDefaults : {showMarker: false} }); } /** * Draw the memory usage flot by data(summary data, or one node's data) * * @param areaid * Which DIV draw this flot * @param titleprefix * Title used name * @param cpupair * The CPU timestamp and value pair * @return Nothing */ function drawMemFlot(areaid, titleprefix, freepair, totalpair){ var use = new Array(); var total = new Array(); var tempsize = 0; var index = 0; $('#' + areaid).empty(); if (freepair.length < totalpair.length) { tempsize = freepair.length; } else { tempsize = freepair.length; } for (index = 0; index < tempsize; index += 2) { var temptotal = totalpair[index + 1]; var tempuse = temptotal - freepair[index + 1]; temptotal = temptotal / 1000000; tempuse = tempuse / 1000000; total.push([totalpair[index] * 1000, temptotal]); use.push([freepair[index] * 1000, tempuse]); } $.jqplot(areaid, [use, total], { title: titleprefix + ' Memory Use Last Hour', axes:{ xaxis:{ renderer : $.jqplot.DateAxisRenderer, numberTicks: 4, tickOptions : { formatString : '%R', show : true } }, yaxis: { min : 0, tickOptions:{formatString : '%.2fG'} } }, legend : { show: true, location: 'nw' }, series:[{label:'Used'}, {label: 'Total'}], seriesDefaults : {showMarker: false} }); } /** * Draw the disk usage flot by data(summary data, or one node's data) * * @param areaid * Which div draw this flot * @param titleprefix * Title used name * @param freepair * The free disk number, Ganglia only logs the free data * @param totalpair * The total disk number * @return Nothing */ function drawDiskFlot(areaid, titleprefix, freepair, totalpair) { var use = new Array(); var total = new Array(); var tempsize = 0; var index = 0; $('#' + areaid).empty(); if (freepair.length < totalpair.length) { tempsize = freepair.length; } else{ tempsize = freepair.length; } for (index = 0; index < tempsize; index += 2) { var temptotal = totalpair[index + 1]; var tempuse = temptotal - freepair[index + 1]; total.push([totalpair[index] * 1000, temptotal]); use.push([freepair[index] * 1000, tempuse]); } $.jqplot(areaid, [use, total], { title: titleprefix + ' Disk Use Last Hour', axes:{ xaxis:{ renderer : $.jqplot.DateAxisRenderer, numberTicks: 4, tickOptions : { formatString : '%R', show : true } }, yaxis: { min : 0, tickOptions:{formatString : '%.2fG'} } }, legend : { show: true, location: 'nw' }, series:[{label:'Used'}, {label: 'Total'}], seriesDefaults : {showMarker: false} }); } /** * Draw the network load flot by data(summary data, or one node's data) * * @param areaid * Which div draw this flot * @param titleprefix * Title used name * @param inpair * The timestamp and value pair for download * @param outpair * The timestamp and value pair for upload * @return Nothing */ function drawNetworkFlot(areaid, titleprefix, inpair, outpair) { var inArray = new Array(); var outArray = new Array(); var index = 0; var maxvalue = 0; var unitname = 'B'; var divisor = 1; for (index = 0; index < inpair.length; index += 2) { if (inpair[index + 1] > maxvalue) { maxvalue = inpair[index + 1]; } } for (index = 0; index < outpair.length; index += 2) { if (outpair[index + 1] > maxvalue) { maxvalue = outpair[index + 1]; } } if (maxvalue > 3000000) { divisor = 1000000; unitname = 'GB'; } else if (maxvalue >= 3000) { divisor = 1000; unitname = 'MB'; } else { //do nothing } for (index = 0; index < inpair.length; index += 2) { inArray.push([(inpair[index] * 1000), (inpair[index + 1] / divisor)]); } for (index = 0; index < outpair.length; index += 2) { outArray.push([(outpair[index] * 1000), (outpair[index + 1] / divisor)]); } $.jqplot(areaid, [inArray, outArray], { title: titleprefix + ' Network Last Hour', axes:{ xaxis:{ renderer : $.jqplot.DateAxisRenderer, numberTicks: 4, tickOptions : { formatString : '%R', show : true } }, yaxis: { min : 0, tickOptions:{formatString : '%d' + unitname} } }, legend : { show: true, location: 'nw' }, series:[{label:'In'}, {label: 'Out'}], seriesDefaults : {showMarker: false} }); } /** * Create node status data * * @param nodesStatus * Node status * @return Nothing */ function createNodeStatusData(nodesStatus) { var nodesArray = nodesStatus.split(';'); var position = 0; var nodename = ''; var index = 0; var tempArray; var tempStr = ''; for (index in nodePath) { delete(nodePath[index]); } for (index in nodeStatus) { delete(nodeStatus[index]); } for (index = 0; index < nodesArray.length; index++) { tempStr = nodesArray[index]; position = tempStr.indexOf(':'); nodename = tempStr.substring(0, position); tempArray = tempStr.substring(position + 1).split(','); nodeStatus[nodename] = tempArray[0]; if (('WARNING' == tempArray[0]) || ('NORMAL' == tempArray[0])){ nodePath[nodename] = tempArray[1]; } } } /** * Draw nodes current status, there are four type: * a. unknown(gray): cannot find save data for this node * b. error(red): got status sometime earlier, but cannot get now * c. warning(orange): heavy load * d. normal(green): normal load * * @return Nothing */ function drawGangliaNodesArea() { var position = 0; // Find out the last child's type and name var currentobj = $('#zoomDiv span:last'); var type = currentobj.attr('name').toLowerCase(); var name = currentobj.text(); position = name.indexOf('('); if (position > -1) { name = name.substr(3, position - 3); } $('#gangliaNodes').empty(); switch (type) { // Draw the node current status case 'blade': case 'cec': case 'rack': case 'other': { drawGangliaNodesAreaPic(type, name); } break; // Draw a summary table case 'all': case 'frame': { drawGangliaNodesAreaTable(type, name); } break; default: break; } } function drawGangliaNodesAreaPic(type, name) { var index = 0; var arraypoint = ''; var templength = 0; var showStr = ''; var nodename = ''; switch(type) { case 'blade': { arraypoint = bladehash[name]; } break; case 'cec': { arraypoint = cechash[name]; } break; case 'rack': { arraypoint = rackhash[name]; } break; case 'other': { arraypoint = otherhash[1]; } default: break; } $('#gangliaNodes').html(''); templength = arraypoint.length; for (index = 0; index < templength; index++) { nodename = arraypoint[index]; switch (nodeStatus[nodename]) { case 'ERROR': showStr = '
  • '; break; case 'WARNING': showStr = '
  • '; break; case 'NORMAL': showStr = '
  • '; break; default: showStr = '
  • '; break; } $('#gangliaNodes ul').append(showStr); } // Bind all normal and warning nodes click event $('.monitornormal,.monitorwarning').bind('click', function() { var nodename = $(this).attr('title'); window.open('ganglianode.php?n=' + nodename + '&p=' + nodePath[nodename], 'nodedetail','height=430,width=950,scrollbars=yes,status =no'); }); } function drawGangliaNodesAreaTable(type, name) { var table = $('
    '); var row = ''; var usedCec = new Object(); var header = $(' NameTypeNormalHeavy LoadErrorUnknown '); table.append(header); if (type == 'all') { for (var i in framehash) { var framename = i; row = '' + framename + 'Frame' + monitorStatAgg('frame', framehash[i]) + ''; table.append(row); for(var j in framehash[i]){ usedCec[framehash[i][j]] = 1; } } for (var i in cechash) { if (usedCec[i]) { continue; } var cecname = i; row = '' + cecname + 'CEC' + monitorStatAgg('cec', cechash[i]) + ''; table.append(row); } for (var i in bladehash) { var bladename = i; row = '' + bladename + 'Blade' + monitorStatAgg('blade', bladehash[i]) + ''; table.append(row); } for (var i in rackhash) { var rackname = i; row = '' + rackname + 'Rack' + monitorStatAgg('rack', rackhash[i]) + ''; table.append(row); } if (otherhash[1].length > 0) { row = 'OtherOther' + monitorStatAgg('other', otherhash[1]) + ''; table.append(row); } } else { for (var i in framehash[name]) { var cecname = framehash[name][i]; row = '' + cecname + '' + 'CEC' + monitorStatAgg('cec', cechash[cecname]) + ''; table.append(row); } } $('#gangliaNodes').append(table); } /** * Update all tab per minute. * * @return Nothing */ function monitorStatAgg(type, inputarray) { var normalnum = 0; var warningnum = 0; var errornum = 0; var nuknownnum = 0; var tempArray; var tempname; switch (type) { case 'blade': case 'cec': case 'rack': case 'other': { tempArray = inputarray; } break; case 'frame': { tempArray = new Array(); for (var i in inputarray){ tempname = inputarray[i]; for (var j in cechash[tempname]) { tempArray.push(cechash[tempname][j]); } } } break; default: return; break; } for (var i in tempArray) { tempname = tempArray[i]; switch(nodeStatus[tempname]) { case 'NORMAL': normalnum++; break; case 'WARNING': warningnum++; break; case 'ERROR': errornum++; break; default: nuknownnum++; break; } } normalnum = normalnum?normalnum:'-'; warningnum = warningnum?warningnum:'-'; errornum = errornum?errornum:'-'; nuknownnum = nuknownnum?nuknownnum:'-'; return ('' + normalnum + '' + warningnum + '' + errornum + '' + nuknownnum + ''); } /** * Update all tab per minute. * * @return Nothing */ function updateGangliaPage() { if ($('#gangliaNodes').size() < 1) { return; } sendGridCurrentAjax(); sendNodeCurrentAjax(); gangliaTimer = window.setTimeout('updateGangliaPage()', 60000); } /** * change the zoom area when click the zoom button * * @return Nothing */ function updateZoom(obj) { var type=$(obj).attr('name'); while ($('#zoomDiv span:last').attr('name') != type) { $('#zoomDiv span:last').remove(); } $(obj).removeClass('monitorzoomlinkli'); $(obj).unbind('click'); drawGangliaNodesArea(); } /** * add the zoom level when click the group link in the summary table * * @return Nothing */ function addZoomDiv(obj) { var name = $(obj).text(); var type = $(obj).attr('name'); var lastzoomobj = $('#zoomDiv span:last'); lastzoomobj.addClass('monitorzoomlink'); lastzoomobj.bind('click', function() { updateZoom(this); }); var newcontent = ' > ' + name + '(' + type.toUpperCase() + ')'; var newli = '' + newcontent + ''; $('#zoomDiv').append(newli); drawGangliaNodesArea(); }