integrate ganglia into xcat gui

git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@10247 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd
This commit is contained in:
xq2005 2011-08-09 09:10:51 +00:00
parent c4eabee332
commit f79fde6d3b
4 changed files with 986 additions and 287 deletions

View File

@ -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;

83
xCAT-UI/ganglianode.php Normal file
View File

@ -0,0 +1,83 @@
<?php
echo <<<EEE
<html>
<head>
<title>Node {$_GET['n']} Ganglia Report</title>
<meta content="600" http-equiv="refresh">
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<link href="css/style.css" rel=stylesheet type="text/css">
<link href="css/jquery.jqplot.css" rel=stylesheet type="text/css">
<script type="text/javascript" src="js/jquery/jquery-1.4.4.min.js"></script>
<script type="text/javascript" src="js/jquery/jquery-ui-1.8.12.start.min.js"></script>
<script type="text/javascript" src="js/ui.js"></script>
EEE;
?>
<script type="text/javascript">
window.onload=function() {
var nodepath = $('#nodepath').val();
includeJs("js/jquery/jquery.jqplot.min.js");
includeJs("js/jquery/jqplot.dateAxisRenderer.min.js");
includeJs("js/jquery/jqplot.dateAxisRenderer.min.js");
includeJs("js/monitor/gangliamon.js");
$.ajax({
url : 'lib/cmd.php',
dataType : 'json',
data : {
cmd : 'webrun',
tgt : '',
args : 'gangliashow;' + nodepath + ';hour;_summary_',
msg : ''
},
success: function(data){
drawNodesummary(data.rsp[0]);
}
});
};
function drawNodesummary(summaryString){
var nodename = $('#nodename').val();
var nodeData = 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(':');
metricname = metricArray[index].substr(0, position);
nodeData[metricname] = new Array();
valueArray = metricArray[index].substr(position + 1).split(',');
tempLength = valueArray.length;
for (var i = 0; i < tempLength; i++){
nodeData[metricname].push(Number(valueArray[i]));
}
}
drawLoadFlot('ganglianodeload', nodename, nodeData['load_one'], nodeData['cpu_num']);
drawCpuFlot('ganglianodecpu', nodename, nodeData['cpu_idle']);
drawMemFlot('ganglianodemem', nodename, nodeData['mem_free'], nodeData['mem_total']);
}
</script>
<?php
echo <<<EEE
</head>
<body>
<input id="nodename" type="hidden" value="{$_GET['n']}"></input>
<input id="nodepath" type="hidden" value="{$_GET['p']}"></input>
<div style="background-color:white;" class="tab">
<table style="border-style:none;">
<tr>
<td style="padding:0;border-style:none;"><div id="ganglianodeload" class="monitorsumdiv"></div></td>
<td style="padding:0;border-style:none;"><div id="ganglianodecpu" class="monitorsumdiv"></div></td>
<td style="padding:0;border-style: none;"><div id="ganglianodemem" class="monitorsumdiv"></div></td>
</tr>
</table>
</div>
</body>
</html>
EEE;
?>

View File

@ -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 = $('<div id="groups"></div>');
var nodes = $('<div id="nodes"></div>');
gangliaTab.append(groups);
gangliaTab.append(nodes);
// Create info bar
var gangliaLnk = $('<a href="#">Click here</a>');
gangliaLnk.css( {
'color' : 'blue',
'text-decoration' : 'none'
});
gangliaLnk.click(function() {
// Open a new window for Ganglia
window.open('../ganglia/');
});
// Create info bar
var info = $('<div class="ui-state-highlight ui-corner-all"></div>');
info.append('<span class="ui-icon ui-icon-info" style="display: inline-block; margin: 10px 5px;"></span>');
var msg = $('<p style="display: inline-block; width: 95%;"></p>');
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 = $('<a href="#">Click here</a>');
startLnk.css( {
'color' : 'blue',
'text-decoration' : 'none'
});
startLnk.click(function() {
// Turn on Ganglia for all nodes
monitorNode('', 'on');
});
// Create warning bar
var warningBar = $('<div class="ui-state-error ui-corner-all"></div>');
var msg = $('<p></p>');
msg.append('<span class="ui-icon ui-icon-alert"></span>');
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('<div class="grouplabel">Groups</div>');
var grouplist= $('<div class="groupdiv"></div>');
// Create a link for each group
for (var i = groups.length; i--;) {
grouplist.append('<div><a href="#">' + groups[i] + '</a></div>');
}
$('#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 = $('<a href="#">Click here</a>');
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 = $('<div class="ui-state-error ui-corner-all"></div>');
var msg = $('<p></p>');
msg.append('<span class="ui-icon ui-icon-alert"></span>');
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 = $('<div id="ganglia_sum"></div>');
$('#nodes').append(summary);
// Create pie details
var details = $('<div id="ganglia_details"></div>');
$('#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 = '<select style="padding:0px;" id="gangliagroup">';
for (var i in groupsArray){
groupsSelectStr += '<option value="' + groupsArray[i] + '">' + groupsArray[i] + '</option>';
}
groupsSelectStr += '</select>';
//help info
var helpStr = '<div class="tooltip">aaa</div>';
//pass checking
var showStr = '<h3>Grid Overview</h3><hr>' +
'<div id="gangliaGridSummary"></div>' +
'<h3 style="display:inline;">Nodes Current Status</h3>' +
'<sup style="cursor: pointer;color:blue"> ?</sup>' +
'<hr>Nodes in Group:' + groupsSelectStr +
' order by: <select id="gangliaorder" style="padding:0px;"><option value="name">Name</option>' +
'<option value="asc">Ascending</option><option value="des">Descending</option></select>' +
'<div id="gangliaNodes"></div>';
//ganglia help information
gangliaTab.append(showStr);
//get summary data and draw on the page
$('#gangliaGridSummary').append('Getting Grid summary Data.<img src="images/loader.gif"></img>');
sendGridSummaryAjax();
//get nodes current status and draw on the page
$('#gangliaNodes').append('Getting ' + $('#gangliagroup').val() + ' nodes Status.<img src="images/loader.gif"></img>');
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.<img src="images/loader.gif"></img>');
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 = '<table>' +
'<tr><td style="background:#66CD00;" width="16px"> </td><td>Normal</td></tr>' +
'<tr><td style="background:#FFD700;" width="16px"> </td><td>Heavy Load</td></tr>' +
'<tr><td style="background:#FF3030;" width="16px"> </td><td>Can not get status longer than 3 minutes</td></tr>' +
'<tr><td style="background:#8B8B7A;" width="16px"> </td><td>Unknown</td></tr>' +
'</table>';
var helpDia = $('<div></div>');
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 = '<table style="border-style:none;"><tr><td style="padding:0;border-style:none;"><div id="gangliasummaryload" class="monitorsumdiv"></div></td>' +
'<td style="padding:0;border-style:none;"><div id="gangliasummarycpu" class="monitorsumdiv"></div></td>' +
'<td style="padding:0;border-style: none;"><div id="gangliasummarymem" class="monitorsumdiv"></div></td></tr></table>';
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('<ul style="margin:0px;padding:0px;"></ul>');
//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 = '<li class="monitorunknown ui-corner-all monitornodeli" ' +
'title="' + nodename + '"></li>';
}
break;
case -1:{
showStr = '<li class="monitorerror ui-corner-all monitornodeli" ' +
'title="' + nodename + '"></li>';
}
break;
case 0:{
showStr = '<li class="mornitorwarning ui-corner-all monitornodeli" ' +
'title="' + nodename + '"></li>';
}
break;
case 1:{
showStr = '<li class="monitornormal ui-corner-all monitornodeli" ' +
'title="' + nodename + '"></li>';
}
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];
}

View File

@ -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];