diff --git a/xCAT-UI/css/style.css b/xCAT-UI/css/style.css
index 9cd1e506f..a9d28c8c2 100644
--- a/xCAT-UI/css/style.css
+++ b/xCAT-UI/css/style.css
@@ -713,11 +713,16 @@ table a:hover {
.monitorsumdiv {
width: 300px;
- height: 150px;
+ height: 180px;
float: left;
- margin: 0px 0px 10px 0px;
+ margin: 0px 0px 10px 10px;
}
+.monitorsumdiv td{
+ padding: 0;
+ border-style: none;
+ font-size: 10px;
+}
.monitornodediv {
width: 240px;
height: 120px;
diff --git a/xCAT-UI/ganglianode.php b/xCAT-UI/ganglianode.php
new file mode 100644
index 000000000..f9907ca82
--- /dev/null
+++ b/xCAT-UI/ganglianode.php
@@ -0,0 +1,83 @@
+
+
+ Node {$_GET['n']} Ganglia Report
+
+
+
+
+
+
+
+EEE;
+?>
+
+
+
+
+
+
+
+
+EEE;
+?>
\ No newline at end of file
diff --git a/xCAT-UI/js/monitor/gangliamon.js b/xCAT-UI/js/monitor/gangliamon.js
index 1aeec021b..69795cdfd 100644
--- a/xCAT-UI/js/monitor/gangliamon.js
+++ b/xCAT-UI/js/monitor/gangliamon.js
@@ -1,8 +1,19 @@
/**
* Global variables
*/
-var gangliaTableId = 'nodesDatatable';
-var gangliaData;
+//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 which is used for sorting
+var nodeStatus = new Object();
+
+//update timer
+var gangliaTimer;
+
/**
* Load Ganglia monitoring tool
@@ -11,61 +22,33 @@ var gangliaData;
*/
function loadGangliaMon() {
// Get Ganglia tab
- var gangliaTab = $('#gangliamon');
+ $('#gangliamon').append(createInfoBar('Checking RPMs.'));
+
+ //should get the groups first
+ 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 ganglia-web'
+ cmd : 'rpm -q rrdtool ganglia-gmetad ganglia-gmond'
},
success : checkGangliaRPMs
});
-
- // Create groups and nodes DIV
- var groups = $('');
- var nodes = $('');
- gangliaTab.append(groups);
- gangliaTab.append(nodes);
-
- // Create info bar
- var gangliaLnk = $('Click here');
- gangliaLnk.css( {
- 'color' : 'blue',
- 'text-decoration' : 'none'
- });
- gangliaLnk.click(function() {
- // Open a new window for Ganglia
- window.open('../ganglia/');
- });
-
- // Create info bar
- var info = $('');
- info.append('');
- var msg = $('');
- msg.append('Select a group to view the nodes summary. ');
- msg.append(gangliaLnk);
- msg.append(' to open the Ganglia page.');
- info.append(msg);
- info.css('margin-bottom', '10px');
- nodes.append(info);
-
- // Get groups
- $.ajax( {
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'extnoderange',
- tgt : '/.*',
- args : 'subgroups',
- msg : ''
- },
-
- success : loadGroups4Ganglia
- });
-
return;
}
@@ -78,10 +61,10 @@ function loadGangliaMon() {
*/
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", "ganglia-web" ];
+ var gangliaRPMs = [ "rrdtool", "ganglia-gmetad", "ganglia-gmond"];
var warningMsg = 'Before continuing, please install the following packages: ';
var missingRPMs = false;
for ( var i in status) {
@@ -99,6 +82,7 @@ function checkGangliaRPMs(data) {
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',
@@ -110,255 +94,598 @@ function checkGangliaRPMs(data) {
msg : ''
},
- /**
- * Append warning message
- *
- * @param data
- * Data returned from HTTP request
- * @return Nothing
- */
- success : function(data) {
- 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 = $('');
- msg.append('');
- msg.append('Please start Ganglia Monitoring on xCAT. ');
- msg.append(startLnk);
- msg.append(' to start Ganglia Monitoring.');
- 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');
- var gangliaTab = $('#gangliamon');
- if (curWarnings.length) {
- curWarnings.after(warningBar);
- } else {
- warningBar.prependTo(gangliaTab);
- }
- }
- }
+ success : checkGangliaRunning
});
}
+
return;
}
/**
- * Load groups
- *
- * @param data
- * Data returned from HTTP request
- * @return
- */
-function loadGroups4Ganglia(data) {
- // Remove loader
- $('#groups').find('img').remove();
-
- // Save group in cookie
- var groups = data.rsp;
- setGroupsCookies(data);
-
- // Create a list of groups
- $('#groups').append('Groups
');
- var grouplist= $('');
- // Create a link for each group
- for (var i = groups.length; i--;) {
- grouplist.append('');
- }
-
- $('#groups').append(grouplist);
-
- // Bind the click event
- $('#groups .groupdiv div').bind('click', function(){
- $('#nodes .jqplot-target').remove();
-
- // Create loader
- var loader = createLoader();
- loader.css('padding', '5px');
- $('#nodes').append(loader);
-
- var thisGroup = $(this).text();
- $('#groups .groupdiv div').removeClass('selectgroup');
- $(this).addClass('selectgroup');
-
- $.ajax( {
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'nodels',
- tgt : thisGroup,
- args : '',
- msg : thisGroup
- },
-
- /**
- * Get node definitions
- *
- * @param data
- * Data returned from HTTP request
- * @return Nothing
- */
- success : function(data) {
- var group = data.msg;
-
- // Get nodes definitions
- $.ajax( {
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'nodestat',
- tgt : group,
- args : '',
- msg : group
- },
-
- success : loadGangliaSummary
- });
- }
- });
- });
-}
-
-/**
- * Load Ganglia summary page
+ * Check whether Ganglia is running
*
* @param data
* Data returned from HTTP request
* @return Nothing
*/
-function loadGangliaSummary(data) {
- // Data returned
- var rsp = data.rsp;
- // Group name
- var group = data.msg;
- // Node attributes hash
- var attrs = new Object();
-
- var node, status, args;
- for ( var i in rsp) {
- // Get key and value
- args = rsp[i].split(':', 2);
- node = jQuery.trim(args[0]);
- status = jQuery.trim(args[1]);
-
- // Create a hash table
- attrs[node] = new Object();
- attrs[node]['status'] = status;
- }
-
- // Save node attributes hash
- gangliaData = attrs;
-
- // Get the status of Ganglia
- // Then create pie chart for node and Ganglia status
- $.ajax( {
- url : 'lib/cmd.php',
- dataType : 'json',
- data : {
- cmd : 'webrun',
- tgt : '',
- args : 'gangliastatus;' + group,
- msg : ''
- },
+function checkGangliaRunning(data){
+ var gangliaTab = $('#gangliamon');
+ var groupsSelectStr = '';
+ var groupsArray = $.cookie('groups').split(',');
+ gangliaTab.empty();
+ 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');
+ });
- success : loadGangliaStatus
- });
-}
+ // Create warning bar
+ var warningBar = $('');
+ var msg = $('');
+ msg.append('');
+ msg.append('Please start Ganglia Monitoring on xCAT. ');
+ msg.append(startLnk);
+ msg.append(' to start Ganglia Monitoring.');
+ warningBar.append(msg);
+ warningBar.css('margin-bottom', '10px');
-/**
- * Load the status of Ganglia for a given group
- *
- * @param data
- * Data returned from HTTP request
- * @return Nothing
- */
-function loadGangliaStatus(data) {
- // Remove loader
- $('#nodes').find('img').remove();
-
- // Get datatable
- var ganglia = data.rsp;
- var node, ping, monitored;
+ // 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;
+ }
- // Count nodes that are pingable and not pingable
- // and nodes that are pingable and monitored by Ganglia
- var pingWGanglia = 0;
- var pingWOGanglia = 0;
- var noping = 0;
- for ( var i in ganglia) {
- // ganglia[0] = nodeName and ganglia[1] = state
- node = jQuery.trim(ganglia[i][0]);
- if (node) {
- monitored = jQuery.trim(ganglia[i][1]);
- ping = gangliaData[node]['status'];
-
- // If the node is monitored, increment count
- if (ping == 'sshd' && monitored == 'on') {
- pingWGanglia++;
- } else if (ping == 'sshd' && monitored == 'off') {
- pingWOGanglia++;
- } else {
- noping++;
- }
- }
- }
-
- // Create pie chart
- var summary = $('');
- $('#nodes').append(summary);
-
- // Create pie details
- var details = $('');
- $('#nodes').append(details);
-
- var pie = [['Ping + monitored', pingWGanglia], ['Ping + not monitored', pingWOGanglia], ['Noping', noping]];
- var plot = $.jqplot('ganglia_sum',
- [pie], {
- seriesDefaults: {
- renderer: $.jqplot.PieRenderer,
- rendererOptions: {
- padding: 5,
- fill:true,
- shadow:true,
- shadowOffset: 2,
- shadowDepth: 5,
- shadowAlpha: 0.07,
- dataLabels : 'value',
- showDataLabels: true
- }
- },
- legend: {
- show: true,
- location: 'e'
+ groupsSelectStr = '';
+
+ //help info
+ var helpStr = 'aaa
';
+
+ //pass checking
+ var showStr = 'Grid Overview
' +
+ '' +
+ 'Nodes Current Status
' +
+ ' ?' +
+ '
Nodes in Group:' + groupsSelectStr +
+ ' order by: ' +
+ '';
+
+ //ganglia help information
+
+ gangliaTab.append(showStr);
+
+ //get summary data and draw on the page
+ $('#gangliaGridSummary').append('Getting Grid summary Data.');
+ sendGridSummaryAjax();
+
+ //get nodes current status and draw on the page
+ $('#gangliaNodes').append('Getting ' + $('#gangliagroup').val() + ' nodes Status.');
+ sendNodeCurrentAjax();
+
+ //start the timer to update page per minute.
+ gangliaTimer = window.setTimeout('updateGangliaPage()', 60000);
+
+ //bind the group select change event
+ $('#gangliagroup').bind('change', function(){
+ var groupname = $(this).val();
+ $('#gangliaNodes').html('Getting ' + groupname + ' nodes Status.');
+ sendNodeCurrentAjax();
+ });
+
+ //bind the order select change event
+ $('#gangliaorder').bind('change', function(){
+ drawGangliaNodesArea($(this).val());
+ });
+
+ //bind the info click enent
+ $('#gangliamon sup').bind('click', function(){
+ var helpStr = '' +
+ ' | Normal |
' +
+ ' | Heavy Load |
' +
+ ' | Can not get status longer than 3 minutes |
' +
+ ' | Unknown |
' +
+ '
';
+ var helpDia = $('');
+ helpDia.append(helpStr);
+ helpDia.dialog({
+ modal: true,
+ width: 350,
+ title: 'Node Status Help Info',
+ close: function(){$(this).remove();},
+ buttons: {
+ 'Close': function(){
+ $(this).dialog('close');
+ }
}
});
-
- // Change CSS styling for legend
- summary.find('table').css({
- 'border-style': 'none'
- }).find('td').css({
- 'border-style': 'none'
- });
+ });
+}
- // Open nodes page on-click
- $('#ganglia_sum').bind('jqplotDataClick', function(env, srIndex, ptIndex, data) {
- window.open('../xcat/index.php');
- });
-
- // Special note
- // To redraw pie chart:
- // - Use chart.series[0].data[i] to reference existing data
- // - Use chart.redraw() to redraw chart
+/**
+ * send ajax request to get grid summary information
+ *
+ * @param
+ *
+ * @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
+ *
+ * @param which group name want to get
+ *
+ * @return Nothing
+ */
+function sendNodeCurrentAjax(){
+ var groupname = $('#gangliagroup').val();
+ //get all nodes current status
+ $.ajax({
+ url : 'lib/cmd.php',
+ dataType : 'json',
+ data : {
+ cmd : 'webrun',
+ tgt : '',
+ args : 'gangliacurrent;node;' + groupname,
+ msg : ''
+ },
+
+ success: function(data){
+ createNodeStatusData(data.rsp[0]);
+ drawGangliaNodesArea($('#gangliaorder').val());
+ }
+ });
+}
+
+/**
+ * send ajax request to get grid current summary information for update the page
+ *
+ * @param
+ *
+ * @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
+ *
+ * @param data
+ * Data returned from HTTP request
+ * @return Nothing
+ */
+function drawGridSummary() {
+ var gridDrawArea = $('#gangliaGridSummary');
+ var showStr = '';
+ var tempStr = $('#gangliamon').attr('class');
+
+ //jqflot only draw on the area visiable, if the tab is hide, return directly
+ if (-1 != tempStr.indexOf('hide')){
+ 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']);
+}
+
+/**
+ * draw the load flot by data(maybe summary data, or one node's data)
+ *
+ * @param areaid: which div draw this flot
+ * loadpair: the load timestamp and value pair
+ * 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 templength = 0;
+ var yaxismax = 0;
+ var interval = 1;
+
+ $('#' + areaid).empty();
+ //parse load pair, the timestamp must mutiply 1000, javascript time stamp is millisecond
+ templength = loadpair.length;
+ for (index = 0; index < templength; index += 2){
+ load.push([loadpair[index] * 1000, loadpair[index + 1]]);
+ if (loadpair[index + 1] > yaxismax){
+ yaxismax = loadpair[index + 1];
+ }
+ }
+
+ //parse cpu pair
+ templength = cpupair.length;
+ for (index = 0; index < templength; 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
+ * titleprefix : title used name
+ * cpupair: the cpu timestamp and value pair
+ *
+ * @return Nothing
+ */
+function drawCpuFlot(areaid, titleprefix, cpupair){
+ var cpu = new Array();
+ var index = 0;
+ var tempLength = 0;
+
+ $('#' + areaid).empty();
+ tempLength = cpupair.length;
+ // time stamp should mutiply 1000
+ // we get the cpu idle from server, we should use 1 subtract the idle.
+ for(index = 0; index < tempLength; 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(maybe summary data, or one node's data)
+ *
+ * @param areaid: which div draw this flot
+ * titleprefix : title used name
+ * 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}
+ }
+ );
+}
+
+function createNodeStatusData(nodesStatus){
+ var index;
+ var nodesArray = nodesStatus.split(';');
+ var position = 0;
+ var nodename = '';
+ var index = 0;
+ var tempArray;
+ var tempStr = '';
+ var templength = nodesArray.length;
+
+ for (index in nodePath){
+ delete(nodePath[index]);
+ }
+
+ for (index in nodeStatus){
+ delete(nodeStatus[index]);
+ }
+
+ for (index = 0; index < templength; index++){
+ tempStr = nodesArray[index];
+ position = tempStr.indexOf(':');
+ nodename = tempStr.substring(0, position);
+ tempArray = tempStr.substring(position + 1).split(',');
+
+ switch(tempArray[0]){
+ case 'UNKNOWN':{
+ nodeStatus[nodename] = -2;
+ }
+ break;
+ case 'ERROR':{
+ nodeStatus[nodename] = -1;
+ }
+ break;
+ case 'WARNING':{
+ nodeStatus[nodename] = 0;
+ nodePath[nodename] = tempArray[1];
+ }
+ break;
+ case 'NORMAL':{
+ nodeStatus[nodename] = 1;
+ nodePath[nodename] = tempArray[1];
+ }
+ break;
+ }
+ }
+}
+/**
+ * draw nodes current status, there are four type:
+ * a. unknown(gray): can not find save data for this node
+ * b. error(red): get status sometime early, but can not get now
+ * c. warning(orange): node are heavy load
+ * d. normal(green):
+ *
+ * @param
+ *
+ * @return Nothing
+ */
+function drawGangliaNodesArea(ordertype){
+ var index = 0;
+ var templength = 0;
+ var showStr = '';
+ var nodename = '';
+ var sortarray = new Array();
+ $('#gangliaNodes').html('');
+ //empty the hash
+ for (index in nodeStatus){
+ sortarray.push([index, nodeStatus[index]]);
+ }
+
+ if ('asc' == ordertype){
+ sortarray.sort(statusAsc);
+ }
+ else if('des' == ordertype){
+ sortarray.sort(statusDes);
+ }
+ else{
+ //do nothing
+ }
+
+ templength = sortarray.length;
+ for (index = 0; index < templength; index++){
+ nodename = sortarray[index][0];
+ switch(sortarray[index][1]){
+ case -2:{
+ showStr = '';
+ }
+ break;
+ case -1:{
+ showStr = '';
+ }
+ break;
+ case 0:{
+ showStr = '';
+ }
+ break;
+ case 1:{
+ 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=250,width=950,scrollbars=yes,status =no');
+ });
+
+}
+
+/**
+ * update all tab per minute.
+ *
+ * @param
+ *
+ * @return Nothing
+ */
+function updateGangliaPage(){
+ if ($('#gangliaNodes').size() < 1){
+ return;
+ }
+
+ sendGridCurrentAjax();
+ sendNodeCurrentAjax();
+
+ gangliaTimer = window.setTimeout('updateGangliaPage()', 60000);
+}
+
+function statusAsc(a, b){
+ return a[1] - b[1];
+}
+
+function statusDes(a, b){
+ return b[1] - a[1];
}
\ No newline at end of file
diff --git a/xCAT-server/lib/xcat/plugins/web.pm b/xCAT-server/lib/xcat/plugins/web.pm
index 9732c685e..027ba6b4d 100644
--- a/xCAT-server/lib/xcat/plugins/web.pm
+++ b/xCAT-server/lib/xcat/plugins/web.pm
@@ -14,12 +14,13 @@ use strict;
require xCAT::Utils;
require xCAT::MsgUtils;
require xCAT::DBobjUtils;
+require IO::Socket::INET;
use Getopt::Long;
use Data::Dumper;
use LWP::Simple;
use xCAT::Table;
use xCAT::NodeRange;
-
+require XML::Parser;
sub handled_commands {
return { webrun => "web", };
}
@@ -51,7 +52,9 @@ sub process_request {
'updatevpd' => \&web_updatevpd,
'createimage' => \&web_createimage,
'provision' => \&web_provision,
- 'summary' => \&web_summay
+ 'summary' => \&web_summay,
+ 'gangliashow' => \&web_gangliaShow,
+ 'gangliacurrent' => \&web_gangliaLatest
);
#check whether the request is authorized or not
@@ -586,6 +589,287 @@ sub web_installganglia() {
return;
}
+#get ganglia data from rrd file.
+#args :
+# nodeRange : the nodes' name which want to get
+# time range : which period want to get, like last hour, last day, last week .....
+# metric : which monitor attribute want to get, like load_one, bytes_in, bytes_out ......
+#
+#output: (till now there are 6 metic to get at one time at most)
+# metric1:timestamp1,value1,timestamp2,value2,.....;metric2:timestamp1,value1,timestamp2,value2,.....;....
+sub web_gangliaShow{
+ my ( $request, $callback, $sub_req ) = @_;
+ my $nodename = $request->{arg}->[1];
+ my $timeRange = 'now-1h';
+ my $resolution = 60;
+ my $metric = $request->{arg}->[3];
+ my @nodes = ();
+ my $retStr = '';
+ my $runInfo;
+ my $cmd = '';
+ my $dirname = '/var/lib/ganglia/rrds/__SummaryInfo__/';
+ #get the summary for this grid(the meaning of grid is referenced from ganglia )
+ if ('_grid_' ne $nodename){
+ $dirname = '/var/lib/ganglia/rrds/' . $nodename . '/';
+ }
+
+ if ('hour' eq $request->{arg}->[2]){
+ $timeRange = 'now-1h';
+ $resolution = 60;
+ }
+ elsif('day' eq $request->{arg}->[2]){
+ $timeRange = 'now-1d';
+ $resolution = 1800;
+ }
+
+ if ('_summary_' eq $metric){
+ my @metricArray = ('load_one', 'cpu_num', 'cpu_idle', 'mem_free', 'mem_total',);
+ my $filename = '';
+ my $step = 1;
+ my $index = 0;
+ my $size = 0;
+ foreach my $tempmetric (@metricArray){
+ my $temp = '';
+ my $line = '';
+ $retStr .= $tempmetric . ':';
+ $filename = $dirname . $tempmetric . '.rrd';
+ $cmd = "rrdtool fetch $filename -s $timeRange -r $resolution AVERAGE";
+ $runInfo = xCAT::Utils->runcmd($cmd, -1, 1);
+ if (scalar(@$runInfo) < 3){
+ $callback->({data=>'error.'});
+ return;
+ }
+ #delete the first 2 lindes
+ shift(@$runInfo);
+ shift(@$runInfo);
+
+ #we only support 60 lines for one metric, in order to reduce the data load for web gui
+ $size = scalar(@$runInfo);
+ if ($size > 60){
+ $step = int($size / 60) + 1;
+ }
+
+ if (($tempmetric eq 'cpu_idle') && ('_grid_' eq $nodename)){
+ my $cpuidle = 0;
+ my $cpunum = 0;
+ for($index = 0; $index < $size; $index += $step){
+ if ($runInfo->[$index] =~ /^(\S+): (\S+) (\S+)/){
+ if (($2 eq 'NaNQ') || ($2 eq 'nan')){
+ #the rrdtool fetch last outline line always nan, so no need to add into return string
+ if ($index == ($size - 1)){
+ next;
+ }
+ $temp .= $1 . ',0,';
+ }
+ else{
+ $cpuidle = sprintf "%.2f", $2;
+ $cpunum = sprintf "%.2f", $3;
+ $temp .= $1 . ',' . (sprintf "%.2f", $cpuidle/$cpunum) . ',';
+ }
+ }
+ }
+ }
+ else{
+ for($index = 0; $index < $size; $index += $step){
+ if ($runInfo->[$index] =~ /^(\S+): (\S+).*/){
+ if (($2 eq 'NaNQ') || ($2 eq 'nan')){
+ #the rrdtool fetch last outline line always nan, so no need to add into return string
+ if ($index == ($size - 1)){
+ next;
+ }
+ $temp .= $1 . ',0,';
+ }
+ else{
+ $temp .= $1 . ',' . (sprintf "%.2f", $2) . ',';
+ }
+ }
+ }
+ }
+ $retStr .= substr($temp, 0, -1) . ';';
+ }
+ $retStr = substr($retStr, 0, -1);
+ $callback->({data=>$retStr});
+ return;
+ }
+}
+
+my $ganglia_return_flag = 0;
+my %gangliaHash;
+my $gangliaclustername;
+my $ganglianodename;
+#use socket to connect ganglia port to get the latest value/status
+sub web_gangliaLatest{
+ my ( $request, $callback, $sub_req ) = @_;
+ my $type = $request->{arg}->[1];
+ my $groupname = '';
+ my $xmlparser;
+ my $telnetcmd = '';
+ my $connect;
+ my $xmloutput = '';
+
+ $ganglia_return_flag = 0;
+ $gangliaclustername = '';
+ $ganglianodename = '';
+ undef(%gangliaHash);
+
+ if($request->{arg}->[2]){
+ $groupname = $request->{arg}->[2];
+ }
+ if ('grid' eq $type){
+ $xmlparser = XML::Parser->new(Handlers=>{Start=>\&web_gangliaGridXmlStart, End=>\&web_gangliaXmlEnd});
+ $telnetcmd = "/?filter=summary\n";
+ }
+ elsif('node' eq $type){
+ $xmlparser = XML::Parser->new(Handlers=>{Start=>\&web_gangliaNodeXmlStart, End=>\&web_gangliaXmlEnd});
+ $telnetcmd = "/\n";
+ }
+
+ #use socket to telnet 127.0.0.1 8652(ganglia's interactive port)
+ $connect = IO::Socket::INET->new('127.0.0.1:8652');
+ unless($connect){
+ $callback->({'data'=>'error: connect local port failed.'});
+ return;
+ }
+
+ print $connect $telnetcmd;
+ while(<$connect>){
+ $xmloutput .= $_;
+ }
+ close($connect);
+
+ $xmlparser->parse($xmloutput);
+
+ if ('grid' eq $type){
+ web_gangliaGridLatest($callback);
+ }
+ elsif('node' eq $type){
+ web_gangliaNodeLatest($callback, $groupname);
+ }
+ return;
+}
+
+#create return data for grid current status
+sub web_gangliaGridLatest{
+ my $callback = shift;
+ my $retStr = '';
+ my $timestamp = time();
+ if ($gangliaHash{'load_one'}){
+ $retStr .= 'load_one:' . $timestamp . ',' . $gangliaHash{'load_one'}->{'SUM'} . ';';
+ }
+ if ($gangliaHash{'cpu_num'}){
+ $retStr .= 'cpu_num:' . $timestamp . ',' . $gangliaHash{'cpu_num'}->{'SUM'} . ';';
+ }
+ if ($gangliaHash{'cpu_idle'}){
+ my $sum = $gangliaHash{'cpu_idle'}->{'SUM'};
+ my $num = $gangliaHash{'cpu_idle'}->{'NUM'};
+ $retStr .= 'cpu_idle:' . $timestamp . ',' . (sprintf("%.2f", $sum/$num )) . ';';
+ }
+ if ($gangliaHash{'mem_total'}){
+ $retStr .= 'mem_total:' . $timestamp . ',' . $gangliaHash{'mem_total'}->{'SUM'} . ';';
+ }
+ if ($gangliaHash{'mem_free'}){
+ $retStr .= 'mem_free:' . $timestamp . ',' . $gangliaHash{'mem_free'}->{'SUM'} . ';';
+ }
+
+ $retStr = substr($retStr, 0, -1);
+ $callback->({data=>$retStr});
+}
+
+#create return data for node current status
+sub web_gangliaNodeLatest{
+ my ($callback, $groupname) = @_;
+ my $node = '';
+ my $retStr = '';
+ my $timestamp = time() - 180;
+ my @nodes;
+ #get all nodes by group
+ if ($groupname){
+ @nodes = xCAT::NodeRange::noderange($groupname, 1);
+ }
+ else{
+ @nodes = xCAT::DBobjUtils->getObjectsOfType('node');
+ }
+ foreach $node(@nodes){
+ #if the node install the ganglia
+ if ($gangliaHash{$node}){
+ my $lastupdate = $gangliaHash{$node}->{'timestamp'};
+ #can not get the monitor data for too long time
+ if ($lastupdate < $timestamp){
+ $retStr .= $node . ':ERROR,Can not get monitor data more than 3 minutes!;';
+ next;
+ }
+
+ if ($gangliaHash{$node}->{'load_one'} > $gangliaHash{$node}->{'cpu_num'}){
+ $retStr .= $node . ':WARNING,';
+ }
+ else{
+ $retStr .= $node . ':NORMAL,';
+ }
+ $retStr .= $gangliaHash{$node}->{'path'} . ';'
+ }
+ else{
+ $retStr .= $node . ':UNKNOWN,;' ;
+ }
+ }
+
+ $retStr = substr($retStr, 0, -1);
+ $callback->({data=>$retStr});
+}
+#xml parser end function, do noting here
+sub web_gangliaXmlEnd{
+}
+
+#xml parser start function for grid latest value
+sub web_gangliaGridXmlStart{
+ my( $parseinst, $elementname, %attrs ) = @_;
+ my $metricname = '';
+
+ #only parser grid infomation
+ if ($ganglia_return_flag){
+ return;
+ }
+ if ('METRICS' eq $elementname){
+ $metricname = $attrs{'NAME'};
+ $gangliaHash{$metricname}->{'SUM'} = $attrs{'SUM'};
+ $gangliaHash{$metricname}->{'NUM'} = $attrs{'NUM'};
+ }
+ elsif ('CLUSTER' eq $elementname){
+ $ganglia_return_flag = 1;
+ return;
+ }
+ else{
+ return;
+ }
+ #only need the grid summary info, if receive cluster return directly
+}
+
+#xml parser start function for node current status
+sub web_gangliaNodeXmlStart{
+ my( $parseinst, $elementname, %attrs ) = @_;
+ my $metricname = '';
+ #save the cluster name
+ if('CLUSTER' eq $elementname){
+ $gangliaclustername = $attrs{'NAME'};
+ return;
+ }
+ elsif('HOST' eq $elementname){
+ if ($attrs{'NAME'} =~ /(\S+?)\.(.*)/){
+ $ganglianodename = $1;
+ }
+ else{
+ $ganglianodename = $attrs{'NAME'};
+ }
+ $gangliaHash{$ganglianodename}->{'path'} = $gangliaclustername . '/' . $attrs{'NAME'};
+ $gangliaHash{$ganglianodename}->{'timestamp'} = $attrs{'REPORTED'};
+ }
+ elsif('METRIC' eq $elementname){
+ $metricname = $attrs{'NAME'};
+ if (('load_one' eq $metricname) || ('cpu_num' eq $metricname)){
+ $gangliaHash{$ganglianodename}->{$metricname} = $attrs{'VAL'};
+ }
+ }
+}
+
sub web_rmcmonStart {
my ( $request, $callback, $sub_req ) = @_;
my $nodeRange = $request->{arg}->[1];