Commit 0a76007b authored by Mike Hibler's avatar Mike Hibler

Script and web interfaces to the new node_history table.

The web interface could use some work...
parent 42655780
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2004 University of Utah and the Flux Group.
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
# All rights reserved.
#
......@@ -19,7 +19,7 @@ BIN_STUFF = power snmpit tbend tbprerun tbreport \
os_load endexp batchexp swapexp \
node_reboot nscheck node_update savelogs node_control \
portstats checkports eventsys_control os_select tbrestart \
tbswap nseswap tarfiles_setup
tbswap nseswap tarfiles_setup node_history
SBIN_STUFF = resetvlans console_setup.proxy sched_reload named_setup \
batch_daemon exports_setup reload_daemon sched_reserve \
......@@ -37,7 +37,7 @@ LIBEXEC_STUFF = rmproj wanlinksolve wanlinkinfo \
os_setup mkexpdir console_setup webnscheck webreport \
webendexp webbatchexp webpanic \
assign_wrapper assign_prepass ptopgen webnodeupdate \
webdelay_config \
webdelay_config webnodehistory \
webrmgroup webswapexp webnodecontrol webeventsys_control \
webmkgroup websetgroups webmkproj \
spewlogfile staticroutes routecalc wanassign \
......
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2005 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use Getopt::Std;
#
# Drill down the node history data in the DB
#
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin:/usr/site/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
# Load the Testbed support stuff.
use lib "@prefix@/lib";
use libdb;
use POSIX qw(ctime);
#
# Magic: Wed Jan 12 13:59:00 2005
# When Leigh implemented the history log.
#
my $epoch = 1105563540;
sub usage {
print("Usage: $0 [-ARalrsvw] [node ...]\n".
" -A print history of all nodes (you do NOT want to do this)\n".
" -R print raw records (default is to combine some records)\n".
" -a show only when allocated to experiment\n".
" -l list records\n".
" -r reverse order (most recent first)\n".
" -s show a summary of node's past usage\n".
" -v verbose output\n".
" -w print warnings about anomolous records\n");
exit(1);
}
my $optlist = "ARalrswv";
my $warnme = 0;
my $verbose = 0;
my $showall = 0;
my $showalloconly = 0;
my $list = 0;
my $summary = 0;
my $raw = 0;
my $revorder = 0;
#
# Parse command arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"A"})) {
$showall = 1;
}
if (defined($options{"R"})) {
$raw = 1;
}
if (defined($options{"a"})) {
$showalloconly = 1;
}
if (defined($options{"l"})) {
$list = 1;
}
if (defined($options{"r"})) {
$revorder = 1;
}
if (defined($options{"s"})) {
$summary = 1;
}
if (defined($options{"w"})) {
$warnme = 1;
}
if (defined($options{"v"})) {
$verbose = 1;
}
if (!$showall && @ARGV == 0) {
usage();
}
my @nodes = @ARGV;
if (!$list && !$summary) {
$list = 1;
}
if ($showall && $summary) {
print STDERR "Cannot summarize for all nodes (yet)\n";
exit(1) if (!$list);
}
#
# Common case: a single node.
# Just fetch data for it, otherwise fetch data for all.
#
my $querymod = "";
if (@nodes == 1) {
$querymod = " AND node_id='$nodes[0]'";
}
# XXX maybe it would be better to sort them here in perl, outside the DB?
my $orderby = " ORDER BY stamp ASC";
my $query_result =
DBQueryFatal("SELECT node_id,stamp,op,uid,pid,eid ".
"FROM node_history,experiment_stats ".
"WHERE node_history.exptidx=experiment_stats.exptidx ".
"$querymod $orderby");
my %nodeinfo; # [ expt, starttime, uid ]
my %nodestats; # [ free, allocated, reloading, down ]
my @lines;
while (my %row = $query_result->fetchhash()) {
my $pideid = "$row{pid}/$row{eid}";
my $node = $row{node_id};
my $stamp = $row{stamp};
my $uid = $row{uid};
#
# XXX if this is the first record for a node, consider it as free
# from the epoch til now.
#
if (!defined($nodeinfo{$node})) {
$nodeinfo{$node} = [ "FREE", $epoch, "root" ];
}
if (!defined($nodestats{$node})) {
$nodestats{$node} = [ 0, 0, 0, 0 ];
}
my ($opideid, $ostamp, $ouid) = @{$nodeinfo{$node}};
my $elapsed = $stamp - $ostamp;
my $start = ctime($ostamp);
my $end = ctime($stamp);
chomp($start);
chomp($end);
#
# Allocating node to experiment.
# Should currently be free.
#
if ($row{op} eq "alloc") {
if ($opideid ne "FREE") {
print STDERR "$node: dup alloc: already in $opideid at $start\n"
if ($warnme);
# XXX possibly missing state in the DB, treat as move
}
$nodeinfo{$node} = [ $pideid, $stamp, $uid ];
}
#
# Free or move terminates a node's time in an experiment.
#
elsif ($row{op} eq "free") {
if ($opideid ne $pideid) {
print STDERR "$node: mismatched alloc,free records: $opideid,$pideid\n"
if ($warnme);
}
$nodeinfo{$node} = [ "FREE", $stamp, $uid ];
}
elsif ($row{op} eq "move") {
if (!$raw) {
# Moves from reloadpending to reloading are combined as reloading
if ($opideid eq "emulab-ops/reloadpending" &&
$pideid eq "emulab-ops/reloading") {
$nodeinfo{$node} = [ $pideid, $ostamp, $ouid ];
next;
}
}
$nodeinfo{$node} = [ $pideid, $stamp, $uid ];
}
my ($ftime, $atime, $rtime, $dtime) = @{$nodestats{$node}};
my $isalloced = 0;
if ($opideid eq "FREE") {
$ftime += $elapsed;
} elsif ($opideid eq "emulab-ops/reloadpending" ||
$opideid eq "emulab-ops/reloading") {
$rtime += $elapsed;
} elsif ($opideid eq "emulab-ops/hwdown") {
$dtime += $elapsed;
} else {
$atime += $elapsed;
$isalloced = 1;
}
$nodestats{$node} = [ $ftime, $atime, $rtime, $dtime ];
if ($list) {
if ($verbose) {
my $str="$node: $opideid from $start til $end ($elapsed sec)\n";
push(@lines, $str)
if (!$showalloconly || $isalloced);
} else {
my ($pid, $eid) = split("/", $opideid);
$eid = "FREE"
if ($pid eq "FREE");
my $str="$node REC $ostamp $elapsed $uid $pid $eid\n";
push(@lines, $str)
if (!$showalloconly || $isalloced);
}
}
}
# Include the current state of nodes
my $stamp = time();
for $node (keys(%nodeinfo)) {
my ($opideid, $ostamp, $ouid) = @{$nodeinfo{$node}};
my $elapsed = $stamp - $ostamp;
my $start = ctime($ostamp);
chomp($start);
my ($ftime, $atime, $rtime, $dtime) = @{$nodestats{$node}};
my $isalloced = 0;
if ($opideid eq "FREE") {
$ftime += $elapsed;
} elsif ($opideid eq "emulab-ops/reloadpending" ||
$opideid eq "emulab-ops/reloading") {
$rtime += $elapsed;
} elsif ($opideid eq "emulab-ops/hwdown") {
$dtime += $elapsed;
} else {
$atime += $elapsed;
$isalloced = 1;
}
$nodestats{$node} = [ $ftime, $atime, $rtime, $dtime ];
if ($list) {
if ($verbose) {
my $str = "$node: $opideid from $start til NOW ($elapsed sec)\n";
push(@lines, $str)
if (!$showalloconly || $isalloced);
} else {
my ($pid, $eid) = split("/", $opideid);
$eid = "FREE"
if ($pid eq "FREE");
my $str="$node REC $ostamp $elapsed $ouid $pid $eid\n";
push(@lines, $str)
if (!$showalloconly || $isalloced);
}
}
}
# Print out list
if ($revorder) {
@lines = reverse(@lines);
}
print @lines;
# Print out summary information
my $node = $nodes[0]; # XXX
if ($summary && defined($nodestats{$node})) {
my ($ftime, $atime, $rtime, $dtime) = @{$nodestats{$node}};
my $ttime = $ftime + $atime + $rtime + $dtime;
if ($verbose) {
my $pct;
print "$node SUMMARY\n";
if ($atime > 0) {
$pct = ($atime * 100) / $ttime;
printf(" Allocted: %9d sec (%5.1f%%)\n", $atime, $pct);
}
if ($ftime > 0) {
$pct = ($ftime * 100) / $ttime;
printf(" Free: %9d sec (%5.1f%%)\n", $ftime, $pct);
}
if ($rtime > 0) {
$pct = ($rtime * 100) / $ttime;
printf(" Reloading: %9d sec (%5.1f%%)\n", $rtime, $pct);
}
if ($dtime > 0) {
$pct = ($dtime * 100) / $ttime;
printf(" Down: %9d sec (%5.1f%%)\n", $dtime, $pct);
}
} else {
print "$node SUM $atime $ftime $rtime $dtime\n";
}
}
exit(0);
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2005 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
#
# This gets invoked from the Web interface. Simply a wrapper ...
#
# usage: webnodehistory arguments ...
#
#
# Configure variables
#
my $TB = "@prefix@";
#
# Run the real thing, and never return.
#
exec "$TB/bin/node_history", @ARGV;
die("webswapexp: Could not exec node_history: $!");
......@@ -131,6 +131,8 @@ if (($isadmin || TBNodeAccessCheck($uid, $node_id, $TB_NODEACCESS_READINFO)) &&
if ($isadmin) {
WRITESUBMENUBUTTON("Show Node Log",
"shownodelog.php3?node_id=$node_id");
WRITESUBMENUBUTTON("Show Node History",
"shownodehistory.php3?node_id=$node_id");
WRITESUBMENUBUTTON("Free Node",
"freenode.php3?node_id=$node_id");
WRITESUBMENUBUTTON("Set Node Location",
......
<?php
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2005 University of Utah and the Flux Group.
# All rights reserved.
#
include("defs.php3");
include("showstuff.php3");
#
# Standard Testbed Header
#
PAGEHEADER("Node History");
#
# Only known and logged in users can do this.
#
$uid = GETLOGIN();
LOGGEDINORDIE($uid);
$isadmin = ISADMIN($uid);
if (!$isadmin) {
USERERROR("Cannot view node history.", 1);
}
#
# Verify form arguments.
#
if (!isset($showall)) {
$showall = 0;
}
if (!isset($node_id) || strcmp($node_id, "") == 0) {
$node_id = "";
} else {
#
# Check to make sure that this is a valid nodeid
#
if (!TBValidNodeName($node_id)) {
USERERROR("$node_id is not a valid node name!", 1);
}
}
echo "<b>Show:
<a href='shownodehistory.php3?node_id=$node_id'>allocated only</a>,
<a href='shownodehistory.php3?node_id=$node_id&showall=1'>all</a>";
SHOWNODEHISTORY($node_id, $showall);
#
# Standard Testbed Footer
#
PAGEFOOTER();
?>
......@@ -1001,28 +1001,6 @@ function SHOWEXPLIST($type,$id,$gid = "") {
}
}
#
# Add a LED like applet that turns on/off based on the output of a URL.
#
# @param uid The logged-in user ID.
# @param auth The value of the user's authentication cookie.
# @param pipeurl The url the applet should connect to to get LED status. This
# string must include any parameters, or if there are none, end with a '?'.
#
# Example:
# SHOWBLINKENLICHTEN($uid,
# $HTTP_COOKIE_VARS[$TBAUTHCOOKIE],
# "ledpipe.php3?node=em1");
#
function SHOWBLINKENLICHTEN($uid, $auth, $pipeurl, $width = 30, $height = 10) {
echo "
<applet code='BlinkenLichten.class' width='$width' height='$height'>
<param name='pipeurl' value='$pipeurl'>
<param name='uid' value='$uid'>
<param name='auth' value='$auth'>
</applet>\n";
}
#
# Show Node information for an experiment.
#
......@@ -2235,6 +2213,132 @@ function SHOWNODE($node_id, $flags = 0) {
echo "</table>\n";
}
#
# Show history.
#
function SHOWNODEHISTORY($node_id, $showall = 0)
{
global $TBSUEXEC_PATH;
$atime = 0;
$ftime = 0;
$rtime = 0;
$dtime = 0;
$opt = "-ls";
if (!$showall) {
$opt .= "a";
}
if ($node_id == "") {
$opt .= "A";
}
if ($fp = popen("$TBSUEXEC_PATH nobody nobody webnodehistory $opt $node_id", "r")) {
if (!$showall) {
$str = "Allocation";
} else {
$str = "";
}
echo "<br>
<center>
$str History for Node $node_id.
</center><br>\n";
echo "<table border=1 cellpadding=2 cellspacing=2 align='center'>\n";
echo "<tr>
<th>Pid</th>
<th>Eid</th>
<th>Allocated By</th>
<th>Allocation Date</th>
<th>Duration</th>
</tr>\n";
$line = fgets($fp);
while (!feof($fp)) {
#
# Formats:
# nodeid REC tstamp duration uid pid eid
# nodeid SUM alloctime freetime reloadtime downtime
#
$results = preg_split("/[\s]+/", $line, 8, PREG_SPLIT_NO_EMPTY);
$nodeid = $results[0];
$type = $results[1];
if ($type == "SUM") {
# Save summary info for later
$atime = $results[2];
$ftime = $results[3];
$rtime = $results[4];
$dtime = $results[5];
} elseif ($type == "REC") {
$stamp = $results[2];
$datestr = date("Y-m-d H:i:s", $stamp);
$duration = $results[3];
$durstr = "";
if ($duration >= (24*60*60)) {
$durstr = sprintf("%dd", $duration / (24*60*60));
$duration %= (24*60*60);
}
if ($duration >= (60*60)) {
$durstr = sprintf("%s%dh", $durstr, $duration / (60*60));
$duration %= (60*60);
}
if ($duration >= 60) {
$durstr = sprintf("%s%dm", $durstr, $duration / 60);
$duration %= 60;
}
$durstr = sprintf("%s%ds", $durstr, $duration);
$uid = $results[4];
$pid = $results[5];
if ($pid == "FREE") {
$pid = "--";
$eid = "--";
$uid = "--";
} else {
$eid = $results[6];
}
echo "<tr>
<td>$pid</td>
<td>$eid</td>
<td>$uid</td>
<td>$datestr</td>
<td>$durstr</td>
</tr>\n";
}
$line = fgets($fp, 1024);
}
pclose($fp);
echo "</table>\n";
$ttime = $atime + $ftime + $rtime + $dtime;
if ($ttime) {
echo "<br>
<center>
Usage Summary for Node $node_id.
</center><br>\n";
echo "<table border=1 align=center>\n";
$str = "Allocated";
$pct = sprintf("%5.1f", $atime * 100.0 / $ttime);
echo "<tr><td>$str</td><td>$pct%</td></tr>\n";
$str = "Free";
$pct = sprintf("%5.1f", $ftime * 100.0 / $ttime);
echo "<tr><td>$str</td><td>$pct%</td></tr>\n";
$str = "Reloading";
$pct = sprintf("%5.1f", $rtime * 100.0 / $ttime);
echo "<tr><td>$str</td><td>$pct%</td></tr>\n";
$str = "Down";
$pct = sprintf("%5.1f", $dtime * 100.0 / $ttime);
echo "<tr><td>$str</td><td>$pct%</td></tr>\n";
echo "</table>\n";
}
}
}
#
# Show log.
#
......@@ -2571,6 +2675,28 @@ function SHOWEXPTSTATS($pid, $eid) {
echo "</table>\n";
}
#
# Add a LED like applet that turns on/off based on the output of a URL.
#
# @param uid The logged-in user ID.
# @param auth The value of the user's authentication cookie.
# @param pipeurl The url the applet should connect to to get LED status. This
# string must include any parameters, or if there are none, end with a '?'.
#
# Example:
# SHOWBLINKENLICHTEN($uid,
# $HTTP_COOKIE_VARS[$TBAUTHCOOKIE],
# "ledpipe.php3?node=em1");
#
function SHOWBLINKENLICHTEN($uid, $auth, $pipeurl, $width = 30, $height = 10) {
echo "
<applet code='BlinkenLichten.class' width='$width' height='$height'>
<param name='pipeurl' value='$pipeurl'>
<param name='uid' value='$uid'>
<param name='auth' value='$auth'>
</applet>\n";
}
#
# This is an included file.
#
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment