Commit fdc02843 authored by Chad Barb's avatar Chad Barb

New visualizer; uses "vis_nodes" table in database to store precomputed solutions.
Added "prerender" call to tbprerun and tbend.
"prerender_all" can be used to precompute vis solutions for all experiments.
Also, removed legacy vis cruft.
parent 68bf3e49
......@@ -398,9 +398,9 @@ outfiles="$outfiles Makeconf GNUmakefile \
utils/firstuser utils/export_tables \
utils/cvsupd.pl \
www/GNUmakefile www/defs.php3 www/dbdefs.php3 \
vis/GNUmakefile vis/vistopology vis/webvistopology vis/top2gif \
vis/dbvistopology vis/dbtopper \
vis/top2png vis/render \
vis/GNUmakefile vis/webvistopology \
vis/dbvistopology \
vis/prerender vis/prerender_all vis/render \
rc.d/GNUmakefile rc.d/2.mysql-server.sh rc.d/3.testbed.sh \
rc.d/2.elvind.sh \
tools/GNUmakefile \
......
......@@ -27,7 +27,7 @@ my $TBROOT = "@prefix@";
# Untaint the path
$ENV{'PATH'} = "/usr/bin:$TBROOT/libexec:$TBROOT/libexec/ns2ir" .
":$TBROOT/sbin:$TBROOT/bin";
":$TBROOT/libexec/vis:$TBROOT/sbin:$TBROOT/bin";
#
# Testbed Support libraries
......@@ -105,6 +105,9 @@ DBQueryWarn("DELETE from ipsubnets where pid='$pid' and eid='$eid'") or
DBQueryWarn("DELETE from ipport_ranges where pid='$pid' and eid='$eid'") or
$errors++;
print "Removing visualization data...\n";
system("prerender -r $pid $eid");
if ($errors == 0) {
SetExpState($pid, $eid, EXPTSTATE_TERMINATED) or
$errors++;
......
......@@ -31,7 +31,7 @@ my $TBROOT = "@prefix@";
# Untaint the path
$ENV{'PATH'} = "/usr/bin:$TBROOT/libexec:$TBROOT/libexec/ns2ir" .
":$TBROOT/sbin:$TBROOT/bin";
":$TBROOT/libexec/vis:$TBROOT/sbin:$TBROOT/bin";
#
# Testbed Support libraries
......@@ -95,6 +95,7 @@ sub cleanup {
DBQueryWarn("DELETE from eventlist where pid='$pid' and eid='$eid'");
DBQueryWarn("DELETE from ipsubnets where pid='$pid' and eid='$eid'");
SetExpState($pid, $eid, EXPTSTATE_NEW);
system("prerender -r $pid $eid");
}
# This setups virt_nodes, virt_names including all IP address calculation
......@@ -109,6 +110,10 @@ if (system("parse-ns $pid $eid $nsfile")) {
TBDebugTimeStamp("parser finished");
print "Parser done! " . TBTimeStamp() . "\n";
TBDebugTimeStamp("prerender started in background");
print "Precomputing visualization (in background)...\n";
system("prerender $pid $eid &");
TBDebugTimeStamp("routes started");
print "Setting up static routes (if requested) ... \n";
if (system("staticroutes $pid $eid")) {
......
......@@ -11,9 +11,9 @@ SUBDIR = vis
include $(OBJDIR)/Makeconf
BIN_SCRIPTS = vistopology dbvistopology
BIN_SCRIPTS = dbvistopology
LIBEXEC_SCRIPTS = webvistopology
LIBEXEC_VIS = topper render top2gif top2png dbtopper
LIBEXEC_VIS = prerender render prerender_all
#
# Force dependencies on the scripts so that they will be rerun through
......
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use Getopt::Std;
use lib '@prefix@/lib';
use libdb;
my $optlist = "d:";
%options = ();
if (! getopts($optlist, \%options)) {
printf( "Usage:\ndbtopper [-d <detaillevel>] <pid> <eid>\n" );
die;
}
my $detail = "0";
if (defined($options{"d"})) {
($options{"d"} =~ /^([0-9]+)$/) or die "argument to -d must be integer, not '$detail'.";
$detail = $1;
}
if (@ARGV != 2) { die "Usage:\ndbtopper [-d <detaillevel>] <pid> <eid>\n"; }
my $pid = $ARGV[0];
my $eid = $ARGV[1];
my $result = DBQueryFatal("SELECT ips, type, vname FROM virt_nodes " .
"WHERE pid='$pid' AND eid='$eid'");
my $nodes = ();
my $links = ();
while (my ($ips, $type, $vname) = $result->fetchrow) {
$ips =~ s/^\d\://g;
$ips =~ s/\s\d\:/ /g;
$ips =~ s/^192\.168//g;
$ips =~ s/\s192\.168/ /g;
$nodes{$vname}{"ips"} = $ips;
$nodes{$vname}{"type"} = $type;
# $nodes{$vname}{"color"} = "skyblue";
}
$result = DBQueryFatal("SELECT vname, delay, bandwidth, lossrate," .
"rdelay, rbandwidth, rlossrate," .
"member FROM virt_lans " .
"WHERE pid='$pid' AND eid='$eid'");
while (my ($vname, $delay, $bandwidth, $lossrate, $rdelay, $rbandwidth, $rlossrate, $member) =
$result->fetchrow) {
$member =~ s/\:.*//;
$links{$vname}{$member}{"delay"} = $delay;
$links{$vname}{$member}{"bw"} = $bandwidth;
$links{$vname}{$member}{"loss"} = $lossrate;
$links{$vname}{$member}{"rdelay"} = $rdelay;
$links{$vname}{$member}{"rbw"} = $rbandwidth;
$links{$vname}{$member}{"rloss"} = $rlossrate;
}
print "graph G {\n";
foreach my $i (keys %nodes) {
my $label = "";
if ($detail > 0) {
$label = $i . "(" . $nodes{$i}{"type"} . ") " . $nodes{$i}{"ips"};
} else {
$label = $i;
}
print "{node [label = \"$label\", shape = box, color = skyblue] " . gvclean($i) . "}\n";
}
foreach my $lan (keys %links) {
if ((keys %{$links{$lan}}) == 2) {
# amalgamate into 2 member link.
my $a = (keys %{$links{$lan}})[0];
my $b = (keys %{$links{$lan}})[1];
my $delaya2b = $links{$lan}{$a}{"delay"} + $links{$lan}{$b}{"rdelay"};
my $delayb2a = $links{$lan}{$b}{"delay"} + $links{$lan}{$a}{"rdelay"};
my $bwa2b = min( $links{$lan}{$a}{"bw"}, $links{$lan}{$b}{"rbw"} );
my $bwb2a = min( $links{$lan}{$b}{"bw"}, $links{$lan}{$a}{"rbw"} );
my $lossa2b = combineloss( $links{$lan}{$a}{"loss"}, $links{$lan}{$b}{"rloss"} );
my $lossb2a = combineloss( $links{$lan}{$b}{"loss"}, $links{$lan}{$a}{"rloss"} );
my $desc = "";
if ($detail > 0) {
$desc = gendesc( $delaya2b, $delayb2a, $bwa2b, $bwb2a, $lossa2b, $lossb2a );
}
print gvclean($a) . " -- " . gvclean($b). " [label = \"$desc\"];\n";
} else {
# make a lan node.
print "{node [label = \"$lan\", shape = box, color = green] " . gvclean($lan) . "}\n";
foreach my $node (keys %{$links{$lan}}) {
my $delayin = $links{$lan}{$node}{"delay"};
my $delayout = $links{$lan}{$node}{"rdelay"};
my $bwin = $links{$lan}{$node}{"bw"};
my $bwout = $links{$lan}{$node}{"rbw"};
my $lossin = $links{$lan}{$node}{"loss"};
my $lossout = $links{$lan}{$node}{"rloss"};
my $desc = "";
if ($detail > 0) {
$desc = gendesc( $delayin, $delayout, $bwin, $bwout, $lossin, $lossout );
}
print gvclean($lan) . " -- " . gvclean($node) . " [label = \"$desc\"];\n";
}
}
}
print "}\n";
exit;
sub min {
my ($a, $b) = @_;
if ($a < $b) { return $a; }
return $b;
}
sub combineloss {
my ($a, $b) = @_;
# print "$a $b";
# $a = $a / 100.0;
# $b = $b / 100.0;
return (1.0 - ((1.0 - $a) * (1.0 - $b)));
}
sub gvclean {
my $n = shift;
$n =~ s/\W/_/g;
$n = "_x1823Y_" . $n;
return $n;
}
sub reportbw {
my $bandwidth = shift;
if ($bandwidth >= 5000000) {
return sprintf( "%.0f", ($bandwidth / 1000000) ) . "Gb";
} elsif ($bandwidth >= 1000000) {
return sprintf( "%.1f", ($bandwidth / 1000000) ) . "Gb";
} elsif ($bandwidth >= 5000) {
return sprintf( "%.0f", ($bandwidth / 1000) ) . "Mb";
} elsif ($bandwidth >= 1000) {
return sprintf( "%.1f", ($bandwidth / 1000) ) . "Mb";
} elsif ($bandwidth >= 5) {
return sprintf( "%.0f", $bandwidth ) . "kb";
} else {
return sprintf( "%.1f", $bandwidth ) . "kb";
}
}
sub reportdelay {
my $delay = shift;
if ($delay == 0) { return "0msec"; }
if ($delay >= 10) {
return sprintf( "%.0f", $delay ) . "msec";
} else {
return sprintf( "%.1f", $delay ) . "msec";
}
}
sub reportloss {
my $losspct = shift;
$losspct *= 100;
if ($losspct < 0.0001) { return "0\%loss"; }
if ($losspct > 5) {
return sprintf( "%.0f", $losspct ) . "\%loss";
} elsif ($losspct > 1) {
return sprintf( "%.1f", $losspct ) . "\%loss";
} elsif ($losspct > 0.1) {
return sprintf( "%.2f", $losspct ) . "\%loss";
} else {
return sprintf( "%.3f", $losspct ) . "\%loss";
}
}
sub gendesc {
my ($delay0, $delay1, $bw0, $bw1, $loss0, $loss1) = @_;
my $desc = "";
if ($bw0 == $bw1) {
$desc .= reportbw( $bw0 ) . " ";
} else {
$desc .= reportbw( $bw0 ) . "/" . reportbw( $bw1 ) . " ";
}
if ($delay0 == $delay1) {
if ($delay0 != 0) {
$desc .= reportdelay( $delay0 ) . " ";
}
} else {
$desc .= reportdelay( $delay0 ) . "/" . reportdelay( $delay1 ) . " ";
}
if ($loss0 == $loss1) {
if ($loss0 != 0.0) {
$desc .= reportloss( $loss0 ) . " ";
}
} else {
$desc .= reportloss( $loss0 ) . "/" . reportloss( $loss1 ) . " ";
}
$desc =~ s/\s$//g;
return $desc;
}
......@@ -32,10 +32,8 @@ use lib "/usr/testbed/lib";
use libdb;
use libtestbed;
my $neato = "neato";
my $dbtopper = "$TB/libexec/vis/dbtopper";
my $render = "$TB/libexec/vis/render";
my $tbdata = "tbdata";
# my $tbdata = "tbdata";
my $output;
my $zoom;
my $detail;
......@@ -129,25 +127,26 @@ if (! TBExptAccessCheck($UID, $pid, $eid, TB_EXPT_READINFO)) {
" You do not have permission to view experiment $pid/$eid\n");
}
my $args;
my $args = "";
if (defined($output)) {
$args = "> $output";
} else {
$args = "2> /dev/null";
}
if (defined($zoom)) {
$args = "-z $zoom $args";
$args .= "-z $zoom ";
}
if (defined($detail)) {
$topperargs = "-d $detail";
$args .= "-d $detail ";
}
$args .= "$pid $eid ";
if (defined($output)) {
$args .= "> $output";
} else {
$topperargs = "";
$args .= "2> /dev/null";
}
if (system("$dbtopper $topperargs $pid $eid | $neato | $render $args") != 0) {
if (system("$render $args") != 0) {
exit(1);
}
......
This diff is collapsed.
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use Getopt::Std;
# Configure variables
my $TB = "@prefix@";
use lib '@prefix@/lib';
use libdb;
# Turn off line buffering on output
$| = 1;
# Untaint the path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
my $PRERENDER_CMD = "@prefix@/libexec/vis/prerender";
sub usage {
die "Usage:\prerender_all [-v]";
}
my $optlist = "v";
%options = ();
if (!getopts($optlist, \%options)) { usage; }
if (@ARGV != 0) { usage; }
if ( defined($options{"v"}) ) {
$PRERENDER_CMD .= " -v";
}
my $result = DBQueryFatal("SELECT pid,eid FROM experiments");
while (my ($pid,$eid) = $result->fetchrow) {
print "Prerendering $pid/$eid\n";
if (system("$PRERENDER_CMD $pid $eid") != 0) {
print STDERR "Prerender of $pid/$eid FAILED!\n";
}
}
exit(0);
This diff is collapsed.
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use Getopt::Std;
#
# Convert a top file into a GIF image.
#
sub usage()
{
print STDOUT "Usage: top2gif [-o <outputfile>] <inputfile>\n".
"Use -o to specify output file. Default to stdout.\n";
exit(-1);
}
my $optlist = "o:";
#
# Configure variables
#
my $TB = "@prefix@";
my $TOPPER = "$TB/libexec/vis/topper";
my $NEATO = "neato";
my $output;
#
# Turn off line buffering on output.
#
$| = 1;
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"o"})) {
$output = $options{"o"};
}
if (@ARGV != 1) {
usage();
}
my $input = $ARGV[0];
if (! -e $input) {
die("*** $0:\n".
" $input does not exist!\n");
}
my $cmd = "cat $input | $TOPPER | $NEATO -Tgif";
if (defined($output)) {
$cmd = "$cmd -o $output";
}
if (system($cmd)) {
exit(1);
}
exit(0);
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use Getopt::Std;
#
# Convert a top file into a PNG image.
#
sub usage()
{
print STDOUT "Usage: top2png [-o <outputfile>] <inputfile>\n".
"Use -o to specify output file. Default to stdout.\n";
exit(-1);
}
my $optlist = "o:";
#
# Configure variables
#
my $TB = "@prefix@";
my $TOPPER = "$TB/libexec/vis/topper";
my $RENDER = "$TB/libexec/vis/render";
my $NEATO = "neato";
my $output;
#
# Turn off line buffering on output.
#
$| = 1;
# un-taint path
$ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Parse command arguments. Once we return from getopts, all that should be
# left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (defined($options{"o"})) {
$output = $options{"o"};
}
if (@ARGV != 1) {
usage();
}
my $input = $ARGV[0];
if (! -e $input) {
die("*** $0:\n".
" $input does not exist!\n");
}
my $cmd = "cat $input | $TOPPER | $NEATO | $RENDER";
if (defined($output)) {
$cmd .= " > $output";
}
if (system($cmd)) {
exit(1);
}
exit(0);
#!/usr/bin/perl -w
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002 University of Utah and the Flux Group.
# All rights reserved.
#
# I can visualize topologies again, topper!
%color = (
"pc850", "skyblue",
"pc600", "steelblue",
"pc", "steelblue",
"shark", "darkblue",
"lan", "green",
"delay", "orange"
);
print "graph G {\n";
while (<>) {
if (/^node/) {
my ($nodename, $nodetype) = /^node\s+(\S+)\s+(\S+)/;
$nodename =~ s/[^\w]/_/g;
print "{node [label = $nodename, shape = box,";
if (exists $color{ $nodetype }) {
print "color = " . $color{ $nodetype };
} else {
warn "Warning! Unknown color for \"$nodetype\"--using default.\n";
print "color = skyblue";
}
print "] $nodename}\n";
} elsif (/^link/) {
my ($lhs, $rhs) = /^link\s+\S+\s+(\S+)\s+(\S+)/;
$rhs =~ s/[^\w]/_/g;
$lhs =~ s/[^\w]/_/g;
print "$lhs -- $rhs;\n";
}
}
print "}\n";
#!/usr/bin/perl -wT
#
# EMULAB-COPYRIGHT
# Copyright (c) 2000-2002 University of Utah and the Flux Group.
# All rights reserved.
#
use English;
use Getopt::Std;
#
# Generate a PNG image of the topology for an experiment.
#
sub usage()
{
print STDOUT
"Usage: vistoplogy [-o <outputfile>] <pid> <eid>\n";
exit(-1);
}
my $optlist = "o:";
#
# Configure variables
#
my $TB = "@prefix@";
#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;
my $top2png = "$TB/libexec/vis/top2png";
my $tbdata = "tbdata";
my $output;
#
# Turn off line buffering on output
#
$| = 1;
#
# Untaint the path
#
$ENV{'PATH'} = '/bin:/usr/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Parse command arguments. Once we return from getopts, all that should
# be left are the required arguments.
#
%options = ();
if (! getopts($optlist, \%options)) {
usage();
}
if (@ARGV != 2) {
usage();
}
my $pid = $ARGV[0];
my $eid = $ARGV[1];
if (defined($options{"o"})) {
$output = $options{"o"};
if ($output =~ /^([-\@\w.\/]+)$/) {
$output = $1;
}
else {
die("Bad data in output name: $output");
}
}
#
# Untaint the arguments.
#
if ($pid =~ /^([-\@\w]+)$/) {
$pid = $1;
}
else {
die("Tainted argument $pid!\n");
}
if ($eid =~ /^([-\@\w]+)$/) {
$eid = $1;
}
else {
die("Tainted argument $eid!\n");
}
#
# Verify existing experiment.
#
if (! ExpState($pid, $eid)) {
die("*** $0:\n".
" No such experiment $pid/$eid\n");
}
#
# Verify that this person is allowed to look at experiment.
#
if (! TBExptAccessCheck($UID, $pid, $eid, TB_EXPT_READINFO)) {
die("*** $0:\n".
" You do not have permission to view experiment $pid/$eid\n");
}
#
# Find out where the experiment directory is.
#
$query_result =
DBQueryFatal("SELECT * FROM experiments WHERE eid='$eid' and pid='$pid'");
if (! $query_result->numrows) {
die("*** $0:\n".
" No experiment record for $pid/$eid exists!\n");
}
my %row = $query_result->fetchhash();
my $estate = $row{'state'};
my $expt_path = $row{'path'};
if ($estate ne EXPTSTATE_ACTIVE && $estate ne EXPTSTATE_SWAPPED) {
die("*** $0:\n".
" Experiment $pid/$eid is not active or swapped!\n");
}
if (! chdir("$expt_path/$tbdata")) {
die("*** $0:\n".
" Could not chdir to $expt_path/$tbdata: $!\n");
}
#
# XXX Temp Hack! Find a top file.
#
my $topfile = "$eid.top";
if (! -e $topfile) {
opendir(DIR, ".");
my @tops = grep { /^.*\.top/ && -f "$_" } readdir(DIR);
closedir DIR;
if (defined($tops[0])) {
$topfile = $tops[0];
# Must taint check!
if ($topfile =~ /^([-\@\w.\/]+)$/) {
$topfile = $1;
}
else {
die("*** $0:\n".
" Bad data in topfile name: $topfile");
}
}
else {
die("*** $0:\n".
" No topfile to graph!\n");
}
}
#
# Run the vis script and be done with it. We don't want stderr to go
# out with the gif file, so just kill that off if redirecting.
#
my $args = $topfile;
if (defined($output)) {