# Part of the Ganglia Project, All Rights Reserved.
#
# Called from index.php, so cluster and xml tree vars
# ($metrics, $clusters, $hosts) are set, and header.php
# already called.
$tpl = new TemplatePower( template("physical_view.tpl") );
$tpl->prepare();
$tpl->assign("cluster",$cluster);
$clusterURL=rawurlencode($cluster);
$tpl->assign("clusterURL",$clusterURL);
# Assign the verbosity level. Can take the value of the 'p' CGI variable.
$verbose = $physical ? $physical : 2;
# The name of the variable changes based on the level. Nice.
$tpl->assign("checked$verbose","checked");
#
# Give the capacities of this cluster: total #CPUs, Memory, Disk, etc.
#
$CPUs = __reduce("cpu_num", __sum, $cluster);
# Divide by 1024^2 to get Memory in GB.
$Memory = sprintf("%.1f GB",__reduce("mem_total", __sum, $cluster)/(float)1048576);
$Disk = __reduce("disk_total", __sum, $cluster);
$Disk = $Disk ? sprintf("%.1f GB", $Disk) : "Unknown";
list($MostFull,$name) = __reduce("part_max_used", __max, $cluster);
$tpl->assign("CPUs", $CPUs);
$tpl->assign("Memory", $Memory);
$tpl->assign("Disk", $Disk);
# Show which node has the most full disk.
$nameurl=rawurlencode($name);
$state = $hosts[$cluster][$name] ? "UP" : "DOWN";
$MostFull = $MostFull ? "$MostFull% Used" : "Unknown";
$tpl->assign("MostFull", $MostFull);
#-------------------------------------------------------------------------------
# Alternate between even and odd row styles.
function rowStyle()
{
static $style;
if ($style == "even") { $style = "odd"; }
else { $style = "even"; }
return $style;
}
#-------------------------------------------------------------------------------
# Displays a rack and all its nodes.
function showrack($ID)
{
global $verbose, $racks, $metrics, $cluster, $clusterURL, $tpl, $clusters;
# An array of [Metrics][Hostname][NAME|VAL|TYPE|UNITS|SOURCE].
$M=$metrics[$cluster];
if ($ID>=0) {
$tpl->assign("RackID","
Rack $ID |
");
}
#
# Scalar helps choose a load color. The lower it is, the easier to get red.
# The highest level occurs at a load of (loadscalar*10).
$loadscalar=0.2;
# A string of node HTML for the template.
$nodes="";
foreach ($racks[$ID] as $node) {
$name=$node[0];
$state=$node[1];
# The metrics we need for this node.
# A megabyte of memory is 1024 KB. This differs from hard drives, where
# one MB = 1000 bytes. Everyone agree this is a bad double-standard?
$mem_totalMB = intval(intval($M[mem_total][$name][VAL])/1024);
$load_one=$M[load_one][$name][VAL];
$cpu_speed=$M[cpu_speed][$name][VAL];
# Choose load color.
$cpu_num=$M[cpu_num][$name][VAL];
if (!$cpu_num) { $cpu_num=1; }
$loadindex=intval($load_one/($loadscalar*$cpu_num))+1;
# 10 is currently the highest allowed load index.
$load= $loadindex > 10 ? "L10" : "L$loadindex";
#
# The nested tables are to get the formatting. Insane.
# We have three levels of verbosity. At L3 we show
# everything; at L1 we only show name and load.
#
# The levels are like HTML tags, we don't tie oursevles
# down to what they exactly mean. The levels are flexible,
# and may mean different things depending on how you are
# viewing them.
#
$rowclass = ($state=="UP") ? rowStyle() : "down";
$nameurl=rawurlencode($name);
$nodes .= "".
"".
"$name \n";
$hardware = "$cpu_num x $cpu_speedMhz, $mem_totalMBMB";
#
# What to show in verbosity level 2.
#
if ($verbose==2) {
$info = $hardware;
}
else if ($verbose > 2) {
$clustertime=$clusters[$cluster][LOCALTIME];
$heartbeat=$M[reported][$name][VAL];
$age = $clustertime - $heartbeat;
$age .= "s";
$info = "Last heartbeat $age ago";
}
#
# Load box.
#
$nodes .= " | ".
"";
if ($verbose>1) {
$nodes .= " | $info";
}
$nodes .= " | \n";
#
# The node hardware.
#
if ($verbose>2) {
$nodes .= $hardware;
}
$nodes .= " |
\n";
$tpl->assign("nodes",$nodes);
}
}
#-------------------------------------------------------------------------------
#
# My Main
#
# 2Key = "Rack ID / Rank (order in rack)" = [hostname, UP|DOWN]
$racks;
#
# Make racks data structure. We try to order the nodes by their physical
# location in the cluster.
#
# If we don't know a node's location, it goes in a negative ID rack.
#
$i=1;
$unknownID=-1;
if (is_array($hosts[$cluster])) {
foreach ($hosts[$cluster] as $host=>$v) {
#
# Try to find the node's location in the cluster.
list($rack, $rank) = findlocation($v);
if ($rack>=0 and $rank>=0) {
$racks[$rack][$rank]=array($v[NAME],"UP");
continue;
}
else {
$i++;
if (! ($i % 25)) {
$unknownID--;
}
$racks[$unknownID][] = array($v[NAME],"UP");
}
}
}
if (is_array($hosts_down[$cluster])) {
foreach ($hosts_down[$cluster] as $host=>$v) {
list($rack, $rank) = findlocation($v);
if ($rack>=0 and $rank>=0) {
$racks[$rack][$rank]=array($v[NAME],"DOWN");
continue;
}
else {
$i++;
if (! ($i % 25)) {
$unknownID--;
}
$racks[$unknownID][] = array($v[NAME],"DOWN");
}
}
}
# Sort the racks array.
if ($unknownID<-1) { krsort($racks); }
else {
ksort($racks);
reset($racks);
while (list($rack,) = each($racks)) {
# In our convention, y=0 is close to the floor.
krsort($racks[$rack]);
}
}
#
# Talk about the location tag if we see alot of unlocated nodes.
#
$Explanation="
".
"Set the LOCATION attribute (in gmond.conf) to get an ordered ".
"view of this page.";
if ($unknownID<-1) {
$tpl->assign("Explanation",$Explanation);
}
# Make a $cols-wide table of Racks.
$cols=5;
$i=1;
foreach ($racks as $rack=>$v) {
$tpl->newBlock("racks");
showrack($rack);
if (! ($i++ % $cols)) {
$tpl->assign("tr","");
}
}
$tpl->printToScreen();
?>