Commit 219f13dd authored by Leigh Stoller's avatar Leigh Stoller

More usability improvements to node history display.

parent ef2ea102
......@@ -2383,7 +2383,8 @@ CREATE TABLE `node_history` (
KEY `stamp` (`stamp`),
KEY `cnet_IP` (`cnet_IP`),
KEY `nodestamp` (`node_id`,`stamp`),
KEY `ipstamp` (`cnet_IP`,`stamp`)
KEY `ipstamp` (`cnet_IP`,`stamp`),
KEY `hid_stamp` (`history_id`,`stamp`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
--
......
#
# Add keys to node_history.
#
use strict;
use libdb;
sub DoUpdate($$$)
{
my ($dbhandle, $dbname, $version) = @_;
if (!DBKeyExists("node_history", "hid_stamp")) {
DBQueryFatal("alter table node_history add " .
" KEY `hid_stamp` (`history_id`,`stamp`)");
}
return 0;
}
1;
# Local Variables:
# mode:perl
# End:
......@@ -52,7 +52,7 @@ sub usage {
exit(1);
}
my $optlist = "ARS:aln:rswvd:i:c";
my $optlist = "ARS:aln:rswvd:i:ct:x:";
my $warnme = 0;
my $verbose = 0;
my $showall = 0;
......@@ -63,6 +63,8 @@ my $summary = 0;
my $raw = 0;
my $numrecs = 0;
my $datetime;
my $datelimit;
my $startrecord;
my $ip;
#
......@@ -126,6 +128,9 @@ if (defined($options{"l"})) {
if (defined($options{"n"})) {
$numrecs = $options{"n"};
}
if (defined($options{"x"})) {
$startrecord = $options{"x"};
}
if (defined($options{"r"})) {
$revorder = 1;
}
......@@ -136,6 +141,16 @@ if (defined($options{"d"})) {
$datetime = timelocal(strptime($options{"d"}));
$summary = 0;
}
if (defined($options{"t"})) {
if (!defined($datetime)) {
$datetime = time() - $options{"t"};
$datelimit = time();
}
else {
$datelimit = $datetime;
$datetime = $datetime - $options{"t"};
}
}
if (defined($options{"c"})) {
$showcurrent = 1;
usage()
......@@ -178,6 +193,7 @@ my %startinfo;
#
if ($datetime) {
my $querymod = "";
if (@nodes) {
$querymod = " AND (" .
join(" or ", map {"h1.node_id='$_'"} @nodes) . ")";
......@@ -188,11 +204,12 @@ if ($datetime) {
my $query_result =
DBQueryFatal("SELECT h1.node_id,h1.op,h1.stamp,h1.uid,h1.exptidx,".
" s.pid,s.eid ".
" s.pid,s.eid,history_id ".
" FROM node_history as h1 ".
"JOIN (SELECT h3.node_id,MAX(h3.stamp) as stamp ".
" FROM node_history as h3 ".
" WHERE stamp < $datetime GROUP BY h3.node_id ".
" WHERE stamp < $datetime ".
" GROUP BY h3.node_id ".
" ) AS h2 ON h1.node_id=h2.node_id AND ".
" h1.stamp = h2.stamp ".
"left join nodes as n on n.node_id=h1.node_id ".
......@@ -211,6 +228,7 @@ if ($datetime) {
my $stamp = $row{stamp};
my $uid = $row{uid};
my $op = $row{op};
my $history_id = $row{"history_id"};
my $cstamp = ctime($stamp);
my $diff = $datetime - $stamp;
chomp($cstamp);
......@@ -224,16 +242,18 @@ if ($datetime) {
print "$node '$stamp' $diff $uid $pid $eid\n";
}
else {
print "$node REC $stamp $diff $uid $pid $eid $exptidx\n";
print "$node REC $stamp $diff $uid $pid $eid ".
"$exptidx $history_id\n";
}
}
else {
$nodeinfo{$node} = [ $pideid, $exptidx, $stamp, $uid ];
$nodeinfo{$node} =
[ $pideid, $exptidx, $stamp, $uid. $history_id ];
}
}
elsif ($op eq "free" || $op eq "destroy") {
if (!$showcurrent) {
$nodeinfo{$node} = [ "", undef, $stamp, $uid ];
$nodeinfo{$node} = [ "", undef, $stamp, $uid, $history_id ];
}
}
}
......@@ -242,25 +262,33 @@ exit(0)
if ($showcurrent);
my $querymod = "";
if ($startrecord) {
$querymod = " AND history_id>='$startrecord'";
}
if (@nodes) {
$querymod = " AND (" . join(" or ", map {"node_id='$_'"} @nodes) . ")";
$querymod .= " AND (" . join(" or ", map {"node_id='$_'"} @nodes) . ")";
}
elsif (defined($ip)) {
$querymod = " AND cnet_ip='$ip'";
$querymod .= " AND cnet_ip='$ip'";
}
# XXX maybe it would be better to sort them here in perl, outside the DB?
my $orderby = " ORDER BY stamp ASC";
# Note that the combo field order by is strictly to convince mysql
# to use an index for sort instead of filesort. I have no idea why
# it does this, but it cuts the query from 70 seconds to under 1 second.
#
my $orderby = " ORDER BY history_id,stamp ASC";
# Bogus, but reading the entire table is nuts! Millions of rows.
my $limitby = ($showall && $numrecs ? "limit " . $numrecs * 100 : "");
my $limitby = ($showall && $numrecs ? "limit " . $numrecs * 10 : "");
my $query_result =
DBQueryFatal("SELECT node_id,stamp,op,uid,pid,eid, ".
" experiment_stats.exptidx,cnet_ip,phys_nodeid ".
" experiment_stats.exptidx,cnet_ip,phys_nodeid,history_id ".
"FROM node_history,experiment_stats ".
"WHERE node_history.exptidx=experiment_stats.exptidx ".
$querymod .
($datetime ? " and stamp>='$datetime' " : "").
"$querymod " .
($datetime ? " and stamp>='$datetime' " : "").
($datelimit ? " and stamp<='$datelimit' " : "").
"$orderby $limitby");
while (my %row = $query_result->fetchhash()) {
......@@ -269,16 +297,17 @@ while (my %row = $query_result->fetchhash()) {
my $node = $row{node_id};
my $stamp = $row{stamp};
my $uid = $row{uid};
my $history_id = $row{"history_id"};
#
# 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} = [ "", undef, $epoch, "root" ];
$nodeinfo{$node} = [ "", undef, $epoch, "root", $history_id ];
}
my ($opideid, $oidx, $ostamp, $ouid) = @{$nodeinfo{$node}};
my ($opideid, $oidx, $ostamp, $ouid, $ohistory_id) = @{$nodeinfo{$node}};
my $elapsed = $stamp - $ostamp;
#
......@@ -291,7 +320,7 @@ while (my %row = $query_result->fetchhash()) {
if ($warnme);
# XXX possibly missing state in the DB, treat as move
}
$nodeinfo{$node} = [ $pideid, $exptidx, $stamp, $uid ];
$nodeinfo{$node} = [ $pideid, $exptidx, $stamp, $uid, $history_id ];
}
#
......@@ -302,18 +331,19 @@ while (my %row = $query_result->fetchhash()) {
print STDERR "$node: mismatched alloc,free records: $opideid,$pideid\n"
if ($warnme);
}
$nodeinfo{$node} = [ "", undef, $stamp, $uid ];
$nodeinfo{$node} = [ "", undef, $stamp, $uid, $history_id ];
}
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, $exptidx, $ostamp, $ouid ];
$nodeinfo{$node} = [ $pideid, $exptidx, $ostamp, $ouid,
$history_id ];
next;
}
}
$nodeinfo{$node} = [ $pideid, $exptidx, $stamp, $uid ];
$nodeinfo{$node} = [ $pideid, $exptidx, $stamp, $uid, $history_id ];
}
elsif ($row{op} eq "create") {
if ($opideid ne "") {
......@@ -321,7 +351,7 @@ while (my %row = $query_result->fetchhash()) {
if ($warnme);
# XXX possibly missing state in the DB.
}
$nodeinfo{$node} = [ $pideid, $exptidx, $stamp, $uid ];
$nodeinfo{$node} = [ $pideid, $exptidx, $stamp, $uid, $history_id ];
}
elsif ($row{op} eq "destroy") {
if ($opideid ne $pideid) {
......@@ -329,21 +359,23 @@ while (my %row = $query_result->fetchhash()) {
"$opideid,$pideid\n"
if ($warnme);
}
$nodeinfo{$node} = [ "", undef, $stamp, $uid ];
$nodeinfo{$node} = [ "", undef, $stamp, $uid, $history_id ];
}
#print "R: $node, $opideid, $oidx, $ouid, $ostamp, $elapsed\n";
# save off the record
push(@rawrecords, [ $node, $opideid, $oidx, $ouid, $ostamp, $elapsed ]);
push(@rawrecords,
[ $node, $opideid, $oidx, $ouid, $ostamp, $elapsed, $ohistory_id ]);
}
if (!$datetime) {
# Include the current state of nodes in a final record
my $stamp = time();
for $node (keys(%nodeinfo)) {
my ($opideid, $oidx, $ostamp, $ouid) = @{$nodeinfo{$node}};
my ($opideid, $oidx, $ostamp, $ouid, $ohistory_id)= @{$nodeinfo{$node}};
my $elapsed = $stamp - $ostamp;
push(@rawrecords, [ $node, $opideid, $oidx, $ouid, $ostamp, $elapsed ]);
push(@rawrecords,
[ $node, $opideid, $oidx, $ouid, $ostamp, $elapsed, $ohistory_id]);
}
}
......@@ -354,7 +386,7 @@ if (!$datetime) {
my @records = ();
for my $rec (@rawrecords) {
my ($node, $pideid, $exptidx, $uid, $stamp, $elapsed) = @{$rec};
my ($node, $pideid, $exptidx, $uid, $stamp, $elapsed, $history_id)= @{$rec};
#print "RR: $node, $elapsed\n";
......@@ -385,7 +417,9 @@ for my $rec (@rawrecords) {
($pid, $eid) = split("/", $pideid);
}
push(@records,
[$node, $stamp, $elapsed, $uid, $pid, $eid, $exptidx, "$pid/$eid"])
[$node, $stamp, $elapsed, $uid, $pid, $eid, $exptidx,
# For sort
"$pid/$eid", $history_id])
if (!$showalloconly || $isalloced);
}
}
......@@ -409,7 +443,8 @@ if ($numrecs && $numrecs < $#records) {
if (@records) {
foreach my $record (@records) {
my ($node, $stamp, $elapsed, $uid, $pid, $eid, $exptidx) = @$record;
my ($node, $stamp, $elapsed, $uid, $pid, $eid,
$exptidx, undef, $history_id) = @$record;
if ($verbose) {
$stamp = ctime($stamp);
......@@ -417,7 +452,8 @@ if (@records) {
print "$node '$stamp' $elapsed $uid $pid $eid\n";
}
else {
print "$node REC $stamp $elapsed $uid $pid $eid $exptidx\n";
print "$node REC $stamp $elapsed $uid $pid $eid ".
"$exptidx $history_id\n";
}
}
}
......
......@@ -1345,9 +1345,9 @@ class Node
#
# Show history.
#
function ShowNodeHistory($node_id = null,
$showall = 0, $count = 20, $reverse = 1,
$date = null, $IP = null) {
function ShowNodeHistory($node_id = null, $record = null,
$count = 200, $showall = 0,
$date = null, $IP = null, $node_opt = "") {
global $TBSUEXEC_PATH;
global $PROTOGENI;
$atime = 0;
......@@ -1356,13 +1356,17 @@ function ShowNodeHistory($node_id = null,
$dtime = 0;
$nodestr = "";
$arg = "";
$opt = "-ls";
$opt = "-ls -n " . escapeshellarg($count);
if (!$showall) {
$opt .= "a";
$opt .= " -a";
}
if ($date) {
$date = date("Y-m-d H:i:s", strtotime($date));
$opt .= " -d " . escapeshellarg($date);
}
elseif ($record) {
$opt .= " -x " . escapeshellarg($record);
}
if ($node_id || $IP) {
if ($IP) {
$opt .= " -i " . escapeshellarg($IP);
......@@ -1373,8 +1377,8 @@ function ShowNodeHistory($node_id = null,
}
}
else {
$node_id = "";
$opt .= " -A";
$node_id = "";
$nodestr = "<th>Node</th>";
#
# When supplying a date, we want a summary of all nodes at that
......@@ -1384,12 +1388,6 @@ function ShowNodeHistory($node_id = null,
$opt .= " -c";
}
}
if ($reverse) {
$opt .= " -r";
}
if ($count) {
$opt .= " -n $count";
}
if ($fp = popen("$TBSUEXEC_PATH nobody nobody ".
" webnode_history $opt $arg", "r")) {
if (!$showall) {
......@@ -1398,31 +1396,21 @@ function ShowNodeHistory($node_id = null,
$str = "";
}
if ($node_id == "") {
echo "<br>
<center><b>
echo "<center><b>
$str History for All Nodes.
</b></center><br>\n";
</b></center>\n";
} else {
$node_url = CreateURL("shownode", URLARG_NODEID, $node_id);
echo "<br>
<center><b>
echo "<center><b>
$str History for Node <a href='$node_url'>$node_id</a>.
</b></center><br>\n";
</b></center>\n";
}
echo "<table border=1 cellpadding=2 cellspacing=2 align='center'>\n";
# Keep track of history record bounds, for paging through.
$max_history_id = 0;
echo "<tr>
$nodestr
<th>Pid</th>
<th>Eid</th>";
if ($PROTOGENI) {
echo "<th>Slice</th>";
}
echo " <th>Allocated By</th>
<th>Allocation Date</th>
<th>Duration</th>
</tr>\n";
# Build up table contents
ob_start();
$line = fgets($fp);
while (!feof($fp)) {
......@@ -1431,7 +1419,7 @@ function ShowNodeHistory($node_id = null,
# nodeid REC tstamp duration uid pid eid
# nodeid SUM alloctime freetime reloadtime downtime
#
$results = preg_split("/[\s]+/", $line, 8, PREG_SPLIT_NO_EMPTY);
$results = preg_split("/[\s]+/", $line, 9, PREG_SPLIT_NO_EMPTY);
$nodeid = $results[0];
$type = $results[1];
if ($type == "SUM") {
......@@ -1460,7 +1448,12 @@ function ShowNodeHistory($node_id = null,
$durstr = sprintf("%s%ds", $durstr, $duration);
$uid = $results[4];
$pid = $results[5];
$thisid = intval($results[8]);
if ($thisid >= $max_history_id) {
$max_history_id = $thisid;
}
$slice = "--";
$expurl = null;
if ($pid == "FREE") {
$pid = "--";
$eid = "--";
......@@ -1468,6 +1461,7 @@ function ShowNodeHistory($node_id = null,
} else {
$eid = $results[6];
if ($results[7]) {
$experiment = Experiment::Lookup($results[7]);
$experiment_stats = ExperimentStats::Lookup($results[7]);
if ($experiment_stats &&
$experiment_stats->slice_uuid()) {
......@@ -1477,6 +1471,15 @@ function ShowNodeHistory($node_id = null,
$slice = "<a href='$url'>" .
"<img src=\"greenball.gif\" border=0></a>";
}
if ($experiment) {
$expurl = CreateURL("showexp",
URLARG_EID, $experiment->idx());
}
else {
$expurl = CreateURL("showexpstats",
"record",
$experiment_stats->exptidx());
}
}
}
......@@ -1485,8 +1488,13 @@ function ShowNodeHistory($node_id = null,
URLARG_NODEID, $nodeid);
echo "<tr>
<td><a href='$nodeurl'>$nodeid</a></td>
<td>$pid</td>
<td>$eid</td>";
<td>$pid</td>";
if ($expurl) {
echo "<td><a href='$expurl'>$eid</a></td>";
}
else {
echo "<td>$eid</td>";
}
if ($PROTOGENI) {
echo "<td>$slice</td>";
}
......@@ -1496,8 +1504,13 @@ function ShowNodeHistory($node_id = null,
</tr>\n";
} else {
echo "<tr>
<td>$pid</td>
<td>$eid</td>";
<td>$pid</td>";
if ($expurl) {
echo "<td><a href='$expurl'>$eid</a></td>";
}
else {
echo "<td>$eid</td>";
}
if ($PROTOGENI) {
echo "<td>$slice</td>";
}
......@@ -1510,8 +1523,29 @@ function ShowNodeHistory($node_id = null,
$line = fgets($fp, 1024);
}
pclose($fp);
$table_html = ob_get_contents();
ob_end_clean();
echo "<center><a href='shownodehistory.php3?record=$max_history_id".
"&count=$count&$node_opt'>Next $count records</a></center>\n";
echo "<table border=1 cellpadding=2 cellspacing=2 align='center'>\n";
echo "<tr>
$nodestr
<th>Pid</th>
<th>Eid</th>";
if ($PROTOGENI) {
echo "<th>Slice</th>";
}
echo " <th>Allocated By</th>
<th>Allocation Date</th>
<th>Duration</th>
</tr>\n";
echo $table_html;
echo "</table>\n";
echo "<center><a href='shownodehistory.php3?record=$max_history_id".
"&count=$count&$node_opt'>Next $count records</a></center>\n";
$ttime = $atime + $ftime + $rtime + $dtime;
if ($ttime) {
......
......@@ -22,9 +22,10 @@ if (! ($isadmin || OPSGUY() || STUDLY())) {
# Verify page arguments.
#
$optargs = OptionalPageArguments("showall", PAGEARG_BOOLEAN,
"reverse", PAGEARG_BOOLEAN,
"count", PAGEARG_INTEGER,
"datetime", PAGEARG_STRING,
"record", PAGEARG_INTEGER,
"count", PAGEARG_INTEGER,
"when", PAGEARG_STRING,
"IP", PAGEARG_STRING,
# To allow for pcvm search, since they are
# transient and will not map to a node.
......@@ -41,18 +42,41 @@ if (!isset($showall)) {
if (!isset($count)) {
$count = 200;
}
if (!isset($reverse)) {
$reverse = 1;
if (!isset($record) || $record == "") {
$record = null;
}
if (isset($record)) {
# Record overrides date/when.
$dateopt = "";
$datetime = null;
$when = null;
}
if (isset($datetime) && $datetime != "") {
elseif (isset($datetime) && $datetime != "") {
if (! strtotime($datetime)) {
USERERROR("Invalid date specified", 1);
}
$dateopt = "&datetime=" . urlencode($datetime);
$record = null;
}
elseif (isset($when) && $when == "yesterday") {
$datetime = date("Y-m-d H:i:s", time() - (24 * 3600));
$dateopt = "&datetime=" . urlencode($datetime);
$record = null;
}
elseif (isset($when) && $when == "lastweek") {
$datetime = date("Y-m-d H:i:s", time() - (7 * 24 * 3600));
$dateopt = "&datetime=" . urlencode($datetime);
$record = null;
}
elseif (isset($when) && $when == "lastmonth") {
$datetime = date("Y-m-d H:i:s", time() - (30 * 24 * 3600));
$dateopt = "&datetime=" . urlencode($datetime);
$record = null;
}
else {
$dateopt = "";
$datetime = null;
$when = "epoch";
}
if (isset($IP)) {
if (! preg_match('/^[0-9\.]+$/', $IP)) {
......@@ -73,12 +97,12 @@ else {
$IP = null;
}
if (isset($node_id)) {
$node_opt = "&node_id=$node_id";
$node_opt = "node_id=$node_id";
$form_opt = "<input type=hidden name=node_id value=$node_id>";
$IP = null;
}
else if (isset($IP)) {
$node_opt = "&IP=$IP";
$node_opt = "IP=$IP";
$form_opt = "<input type=hidden name=IP value=$IP>";
$node_id = null;
}
......@@ -89,7 +113,7 @@ else {
$node_id = null;
}
$opts="count=$count&reverse=$reverse$node_opt$dateopt";
$opts="$node_opt$dateopt";
echo "<b>Show records:</b> ";
if ($showall) {
echo "<a href='shownodehistory.php3?$opts'>allocated only</a>,
......@@ -99,32 +123,31 @@ if ($showall) {
<a href='shownodehistory.php3?$opts&showall=1'>all</a>";
}
$opts="count=$count&showall=$showall$node_opt$dateopt";
echo "<br><b>Order by:</b> ";
if ($reverse == 0) {
echo "<a href='shownodehistory.php3?$opts&reverse=1'>lastest first</a>,
earliest first";
} else {
echo "lastest first,
<a href='shownodehistory.php3?$opts&reverse=0'>earliest first</a>";
$opts="$node_opt&showall=$showall$dateopt";
echo "<br><b>Show:</b> ";
if ($when == "lastmonth") {
echo "Last Month, ";
}
$opts="showall=$showall&reverse=$reverse$node_opt$dateopt";
echo "<br><b>Show number:</b> ";
if ($count != 200) {
echo "<a href='shownodehistory.php3?$opts&count=200'>first 200</a>, ";
} else {
echo "first 200, ";
else {
echo "<a href='shownodehistory.php3?$opts&when=lastmonth'>Last Month</a>, ";
}
if ($count != -200) {
echo "<a href='shownodehistory.php3?$opts&count=-200'>last 200</a>, ";
} else {
echo "last 200, ";
if ($when == "lastweek") {
echo "Last Week, ";
}
if ($count != 0) {
echo "<a href='shownodehistory.php3?$opts&count=0'>all</a>";
} else {
echo "all";
else {
echo "<a href='shownodehistory.php3?$opts&when=lastweek'>Last Week</a>, ";
}
if ($when == "yesterday") {
echo "Yesterday, ";
}
else {
echo "<a href='shownodehistory.php3?$opts&when=yesterday'>Yesterday</a>, ";
}
if ($when == "Epoch") {
echo "Epoch";
}
else {
echo "<a href='shownodehistory.php3?$opts&when=epoch'>Epoch</a>";
}
#
......@@ -139,7 +162,7 @@ echo "<tr><form action=shownodehistory.php3 method=get>
size=20
value=\"" . ($datetime ? $datetime : "mm/dd/yy HH:MM") . "\"></td>
<input type=hidden name=showall value=$showall>
<input type=hidden name=reverse value=$reverse>
<input type=hidden name=when value=$when>
$form_opt
<td class=stealth>
<b><input type=submit name=search1 value=Search></b></td>\n";
......@@ -151,7 +174,7 @@ echo "<tr><form action=shownodehistory.php3 method=get>
size=20
value=\"$node_id\"></td>
<input type=hidden name=showall value=$showall>
<input type=hidden name=reverse value=$reverse>
<input type=hidden name=when value=$when>
<td class=stealth>
<b><input type=submit name=search2 value=Search></b></td>\n";
echo "</form></tr>\n";
......@@ -162,13 +185,13 @@ echo "<tr><form action=shownodehistory.php3 method=get>
size=20
value=\"$IP\"></td>
<input type=hidden name=showall value=$showall>
<input type=hidden name=reverse value=$reverse>
<input type=hidden name=when value=$when>
<td class=stealth>
<b><input type=submit name=search3 value=Search></b></td>\n";
echo "</form></tr>\n";
echo "</table><br>\n";
ShowNodeHistory($node_id, $showall, $count, $reverse, $datetime, $IP);
ShowNodeHistory($node_id, $record, $count, $showall, $datetime, $IP, $node_opt);
#
# Standard Testbed Footer
......
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