All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

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