Commit 4d420b21 authored by Leigh Stoller's avatar Leigh Stoller

Rework of the batch experiment code. Unified it with the immediate

experiment code. No longer uses another table. Rather, the experiment
record contains a couple of extra fields for the batch system. Also
combined some of the backend code (no longer a killbatch script).
Also added scriptable experiments; the batchexp program in the bin
directory can start an experiment from the command line, and in fact
is used from the web page for both batch experiments and immediate
experiments (-i option). All of the DB code that was in the web
interfaces was moved to batchexp.
parent 0fac2e7e
......@@ -1037,8 +1037,8 @@ outfiles="$outfiles Makeconf GNUmakefile \
tbsetup/node_reboot tbsetup/webnscheck tbsetup/nscheck \
tbsetup/resetvlans tbsetup/rmacct-ctrl tbsetup/rmproj \
tbsetup/sched_reload tbsetup/sched_reserve tbsetup/reload_daemon \
tbsetup/batchexp tbsetup/killbatchexp tbsetup/batch_daemon \
tbsetup/webbatchexp tbsetup/webkillbatchexp tbsetup/webreport \
tbsetup/batchexp tbsetup/batch_daemon \
tbsetup/webbatchexp tbsetup/webreport \
tbsetup/startexp tbsetup/endexp tbsetup/webstartexp tbsetup/webendexp \
tbsetup/snmpit tbsetup/ns2ir/GNUmakefile \
tbsetup/ns2ir/parse.tcl tbsetup/ns2ir/tb_compat.tcl \
......
......@@ -159,8 +159,8 @@ outfiles="$outfiles Makeconf GNUmakefile \
tbsetup/node_reboot tbsetup/webnscheck tbsetup/nscheck \
tbsetup/resetvlans tbsetup/rmacct-ctrl tbsetup/rmproj \
tbsetup/sched_reload tbsetup/sched_reserve tbsetup/reload_daemon \
tbsetup/batchexp tbsetup/killbatchexp tbsetup/batch_daemon \
tbsetup/webbatchexp tbsetup/webkillbatchexp tbsetup/webreport \
tbsetup/batchexp tbsetup/batch_daemon \
tbsetup/webbatchexp tbsetup/webreport \
tbsetup/startexp tbsetup/endexp tbsetup/webstartexp tbsetup/webendexp \
tbsetup/snmpit tbsetup/ns2ir/GNUmakefile \
tbsetup/ns2ir/parse.tcl tbsetup/ns2ir/tb_compat.tcl \
......
......@@ -51,7 +51,8 @@ use Exporter;
EXPTSTATE_ACTIVATING EXPTSTATE_ACTIVE EXPTSTATE_TESTING
EXPTSTATE_TERMINATING EXPTSTATE_TERMINATED
BATCHSTATE_POSTED BATCHSTATE_RUNNING BATCHSTATE_TERMINATED
BATCHSTATE_POSTED BATCHSTATE_RUNNING BATCHSTATE_TERMINATING
BATCHSTATE_ACTIVATING
TBBatchState TBSetBatchState
TBAdmin TBProjAccessCheck TBNodeAccessCheck TBOSIDAccessCheck
......
......@@ -11,7 +11,7 @@ include $(OBJDIR)/Makeconf
SUBDIRS = checkpass ns2ir
BIN_STUFF = power snmpit tbend tbswapin tbswapout tbprerun tbreport \
os_load savevlans startexp endexp batchexp killbatchexp \
os_load savevlans startexp endexp batchexp \
node_reboot nscheck node_update savelogs
# Stuff that mere users get on plastic.
......@@ -24,7 +24,7 @@ SBIN_STUFF = resetvlans console_setup.proxy sched_reload named_setup \
LIBEXEC_STUFF = mkprojdir rmproj mkacct-ctrl rmacct-ctrl \
os_setup mkexpdir console_setup webnscheck webreport \
webstartexp webendexp webbatchexp webkillbatchexp \
webstartexp webendexp webbatchexp \
assign_wrapper ptopgen webnodeupdate webgroupupdate \
webrmgroup
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
#!/usr/bin/perl -wT
use English;
use Getopt::Std;
#
# Cancel batch experiment.
#
sub usage()
{
print STDOUT "Usage: killbatchexp $pid $eid\n";
exit(-1);
}
my $optlist = "";
#
# Configure variables
#
my $TB = "@prefix@";
my $batchdir = "$TB/batch";
#
# Testbed Support libraries
#
use lib "@prefix@/lib";
use libdb;
use libtestbed;
#
# Untaint the path
#
$ENV{'PATH'} = "/bin:/usr/bin";
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
#
# Turn off line buffering on output
#
$| = 1;
#
# 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];
#
# 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");
}
#
# This is where we currently hold the batch goo.
#
my $dirname = "$batchdir/$pid-$eid";
#
# Need to lock the table for this. We could avoid the locking if we just
# set the canceled bit and let the batch_daemon clean things up, but that
# introduces needless (and annoying) delay when killing a batch experiment
# that is not even running. See corresponding lock in the batch_daemon.
#
DBQueryFatal("lock tables batch_experiments write");
#
# Set the canceled state right away. This will prevent the batch_daemon
# from trying to run it. It might already be running, but thats okay.
#
DBQueryFatal("UPDATE batch_experiments set canceled=1 ".
"WHERE eid='$eid' and pid='$pid'");
#
# Now its safe to look at the state. If its in the "new" state, then
# all we need to do is kill the record and the directory, since the
# batch daemon will not bother with it once the canceled bit is set.
#
$query_result =
DBQueryFatal("SELECT status from batch_experiments ".
"WHERE eid='$eid' and pid='$pid'");
DBQueryFatal("unlock tables");
@row = $query_result->fetchrow_array();
$state = $row[0];
if ($state ne "new") {
#
# Daemon does the rest ...
#
print STDOUT
"Batch Experiment $eid in project $pid is running on the testbed\n".
"You will receive email notification when the experiment is torn\n".
"down and you can reuse the experiment name\n";
#
# exit status is special. Tells the caller that cancelation is pending.
# The web script will say something useful.
#
exit(1);
}
#
# Delete the DB record. LOCKING!
#
DBQueryFatal("DELETE from batch_experiments WHERE eid='$eid' and pid='$pid'");
#
# And kill the directory.
#
system("rm -rf $dirname");
#
# Lets not bother with an email message. Just print out something nice
# and tell the caller (the php script) to say something nice too).
#
print STDOUT
"Batch Experiment $eid in project $pid has been canceled!\n";
exit(0);
......@@ -21,7 +21,7 @@ use Exporter;
#
sub SENDMAIL($$$;$$@)
{
my($To, $Subject, $Message, $From, $Headers, $Files) = @_;
my($To, $Subject, $Message, $From, $Headers, @Files) = @_;
if (! open(MAIL, "|/usr/sbin/sendmail -t")) {
print STDERR "SENDMAIL: Could not start sendmail: $!\n";
......@@ -46,7 +46,7 @@ sub SENDMAIL($$$;$$@)
if (defined(@Files)) {
foreach my $file ( @Files ) {
if (open(IN, "$file")) {
print MAIL "\n\n--------- $file --------\n\n";
print MAIL "\n--------- $file --------\n";
while (<IN>) {
print MAIL "$_";
......
This diff is collapsed.
#!/usr/bin/perl -w
use English;
#
# This gets invoked from the Web interface. Simply a wrapper.
#
# usage: webkillbatchexp arguments ...
#
#
# Configure variables
#
my $TB = "@prefix@";
#
# Run the real thing, and never return.
#
exec "$TB/bin/killbatchexp", @ARGV;
die("webkillbatchexp: Could not exec killbatchexp: $!");
......@@ -20,11 +20,11 @@ if (!isset($exp_pid) ||
}
if (!isset($exp_id) ||
strcmp($exp_id, "") == 0) {
FORMERROR("Experiment Name (short)");
FORMERROR("Experiment Name");
}
if (!isset($exp_name) ||
strcmp($exp_name, "") == 0) {
FORMERROR("Experiment Name (long)");
FORMERROR("Experiment Description");
}
#
......@@ -107,8 +107,6 @@ elseif ($specupload) {
#
# Make sure the PID/EID tuple does not already exist in the database.
# It may not exist in either the current experiments list, or the
# batch experiments list.
#
$query_result =
DBQueryFatal("SELECT eid FROM experiments ".
......@@ -118,14 +116,6 @@ if (mysql_num_rows($query_result)) {
"in use in project $exp_pid. Please select another.", 1);
}
$query_result =
DBQueryFatal("SELECT eid FROM batch_experiments ".
"WHERE eid='$exp_id' and pid='$exp_pid'");
if (mysql_num_rows($query_result)) {
USERERROR("The batch experiment name '$exp_id' you have chosen is ".
"already in use in project $exp_pid. Please select another.", 1);
}
#
# Check group. If none specified, then use default group.
#
......@@ -141,7 +131,7 @@ if (!TBValidGroup($exp_pid, $exp_gid)) {
# Verify permissions.
#
if (! TBProjAccessCheck($uid, $exp_pid, $exp_gid, $TB_PROJECT_CREATEEXPT)) {
USERERROR("You do not have permission to begin a batch experiment in "
USERERROR("You do not have permission to begin a batch experiment in ".
"in Project/Group $exp_pid/$exp_gid!", 1);
}
......@@ -150,37 +140,6 @@ if (! TBProjAccessCheck($uid, $exp_pid, $exp_gid, $TB_PROJECT_CREATEEXPT)) {
#
TBGroupUnixInfo($exp_pid, $exp_gid, $unix_gid, $unix_name);
#
# Create a temporary file with the goo in it.
#
$tmpfname = tempnam( "/tmp", "batch-$pid-$eid" );
$fp = fopen($tmpfname, "w");
if (! $fp) {
TBERROR("Opening temporary file $tmpfname.", 1);
}
#
# XXX The batchexp script parses this file, so if you change something
# here, go change it there too!
#
fputs($fp, "EID: $exp_id\n");
fputs($fp, "PID: $exp_pid\n");
fputs($fp, "GID: $exp_gid\n");
fputs($fp, "name: $exp_name\n");
fputs($fp, "expires: $exp_expires\n");
fputs($fp, "nsfile: $nsfile\n");
fclose($fp);
#
# XXX
# Set the permissions on the batch file so that the scripts can get to it.
# It is owned by nobody, and most likely protected. This leaves the
# file open for a short time. A potential security hazard we should
# deal with at some point, but since the files are on paper:/tmp, its
# a minor problem.
#
chmod($tmpfname, 0666);
echo "<center><br>";
echo "<h2>Starting batch experiment setup. Please wait a moment ...
</h2></center>";
......@@ -196,14 +155,11 @@ $output = array();
$retval = 0;
$last = time();
$result = exec("$TBSUEXEC_PATH $uid $unix_gid webbatchexp $tmpfname",
$result = exec("$TBSUEXEC_PATH $uid $unix_gid ".
"webbatchexp -x \"$exp_expires\" -E \"$exp_name\" ".
"-p $exp_pid -g $exp_gid -e $exp_id $nsfile",
$output, $retval);
#
# Kill the tempfile since the script will have copied it by now.
#
unlink($tmpfname);
if ($retval) {
echo "<br><br><h2>
Setup Failure($retval): Output as follows:
......
......@@ -20,11 +20,11 @@ if (!isset($exp_pid) ||
}
if (!isset($exp_id) ||
strcmp($exp_id, "") == 0) {
FORMERROR("Experiment Name (short)");
FORMERROR("Experiment Name");
}
if (!isset($exp_name) ||
strcmp($exp_name, "") == 0) {
FORMERROR("Experiment Name (long)");
FORMERROR("Experiment Description");
}
#
......@@ -128,15 +128,6 @@ if (mysql_num_rows($query_result)) {
"in use in project $exp_pid. Please select another.", 1);
}
$query_result =
DBQueryFatal("SELECT eid FROM batch_experiments ".
"WHERE eid='$exp_id' and pid='$exp_pid'");
if (mysql_num_rows($query_result)) {
USERERROR("The experiment name '$exp_id' you have chosen is a current ".
"batch mode experiment in project $exp_pid. ".
"Please select another name.", 1);
}
#
# Check group. If none specified, then use default group.
#
......@@ -174,23 +165,6 @@ else {
$exp_shared = 0;
}
#
# At this point enter the exp_id into the database so that it shows up as
# valid when the tb scripts run. We need to remove the entry if any of
# this fails!
#
DBQueryFatal("INSERT INTO experiments ".
"(eid, pid, gid, expt_created, expt_expires, expt_name, ".
"expt_head_uid, state, shared) ".
"VALUES ('$exp_id', '$exp_pid', '$exp_gid', now(), ".
" '$exp_expires', ".
" '$exp_name', '$uid', '$expt_state', $exp_shared)");
#
# This is where the experiment hierarchy is going to be created.
#
$dirname = "$TBPROJ_DIR/$exp_pid/exp/$exp_id";
#
# Grab the unix GID for running scripts.
#
......@@ -203,7 +177,22 @@ TBGroupUnixInfo($exp_pid, $exp_gid, $unix_gid, $unix_name);
# to clear it out of the database.
#
if ($nonsfile) {
$retval = SUEXEC($uid, $unix_gid, "mkexpdir $exp_pid $exp_id", 0);
#
# Stub Experiment record. Should do this elsewhere?
#
DBQueryFatal("INSERT INTO experiments ".
"(eid, pid, gid, expt_created, expt_expires, expt_name, ".
"expt_head_uid, state, shared) ".
"VALUES ('$exp_id', '$exp_pid', '$exp_gid', now(), ".
" '$exp_expires', ".
" '$exp_name', '$uid', '$expt_state', $exp_shared)");
#
# This is where the experiment hierarchy is going to be created.
#
$dirname = "$TBPROJ_DIR/$exp_pid/exp/$exp_id";
$retval = SUEXEC($uid, $unix_gid, "mkexpdir $exp_pid $exp_gid $exp_id", 0);
echo "<center><br>
<h2>Experiment Configured!</h2>
......@@ -262,7 +251,8 @@ $last = time();
set_time_limit(0);
$result = exec("$TBSUEXEC_PATH $uid $unix_gid ".
"webstartexp -g $exp_gid $exp_pid $exp_id $nsfile",
"webbatchexp -i -x \"$exp_expires\" -E \"$exp_name\" ".
"-p $exp_pid -g $exp_gid -e $exp_id $nsfile",
$output, $retval);
if ($retval) {
......@@ -276,9 +266,6 @@ if ($retval) {
}
echo "</XMP>\n";
$query_result = mysql_db_query($TBDBNAME,
"DELETE FROM experiments WHERE eid='$exp_id' and pid=\"$exp_pid\"");
PAGEFOOTER();
die("");
}
......
......@@ -17,8 +17,9 @@ $TBDB_UNIXGLEN = 16;
#
$TBDB_EIDLEN = 19;
$TBDB_OSID_OSIDLEN = 30;
$TBDB_OSID_VERSLEN = 12;
$TBDB_OSID_OSIDLEN = 30;
$TBDB_OSID_VERSLEN = 12;
$TBDB_IMAGEID_IMAGEIDLEN = 30;
#
# Trust. Define the trust level as an increasing value. Then define a
......
<?php
include("defs.php3");
#
# Standard Testbed Header
#
PAGEHEADER("Cancel a Batch Mode Experiment");
#
# Only known and logged in users can end experiments.
#
$uid = GETLOGIN();
LOGGEDINORDIE($uid);
$isadmin = ISADMIN($uid);
#
# Must provide the EID!
#
if (!isset($exp_pideid) ||
strcmp($exp_pideid, "") == 0) {
USERERROR("The experiment ID was not provided!", 1);
}
#
# First get the project (PID) from the form parameter, which came in
# as <pid>$$<eid>.
#
$exp_eid = strstr($exp_pideid, "\$\$");
$exp_eid = substr($exp_eid, 2);
$exp_pid = substr($exp_pideid, 0, strpos($exp_pideid, "\$\$", 0));
#
# Check to make sure thats this is a valid PID/EID tuple.
#
if (! TBValidBatch($exp_pid, $exp_eid)) {
USERERROR("The experiment $exp_eid is not a valid batch mode experiment ".
"in project $exp_pid.", 1);
}
#
# Verify Permission.that this uid is a member of the project for the experiment
# being displayed, or is an admin type.
#
if (! $isadmin &&
! TBExptAccessCheck($uid, $exp_pid, $exp_eid, $TB_EXPT_DESTROY)) {
USERERROR("You do not have permission to end batch experiments in ".
"project/group $exp_pid/$exp_gid!", 1);
}
#
# We run this twice. The first time we are checking for a confirmation
# by putting up a form. The next time through the confirmation will be
# set. Or, the user can hit the cancel button, in which case we should
# probably redirect the browser back up a level.
#
if ($canceled) {
echo "<center><h2><br>
Batch Mode Experiment, Cancelation Canceled!
</h2></center>\n";
PAGEFOOTER();
return;
}
if (!$confirmed) {
echo "<center><h2><br>
Are you <b>REALLY</b>
sure you want to cancel Batch Mode Experiment '$exp_eid?'
</h2>\n";
echo "<form action=\"endbatch.php3\" method=\"post\">";
echo "<input type=hidden name=exp_pideid value=\"$exp_pideid\">\n";
echo "<b><input type=submit name=confirmed value=Confirm></b>\n";
echo "<b><input type=submit name=canceled value=Cancel></b>\n";
echo "</form>\n";
echo "</center>\n";
PAGEFOOTER();
return;
}
#
# We need the gid.
#
$query_result =
DBQueryFatal("SELECT gid FROM batch_experiments WHERE ".
"eid='$exp_eid' and pid='$exp_pid'");
$row = mysql_fetch_array($query_result);
$exp_gid = $row[gid];
#
# and the unix stuff.
#
TBGroupUnixInfo($exp_pid, $exp_gid, $unix_gid, $unix_name);
#
# We run a wrapper script that does all the work of terminating the
# experiment.
#
echo "<center><br>";
echo "<h3>Starting Batch Mode Experiment Cancelation. Please wait a moment ...
</h3></center>\n";
flush();
#
# Run the scripts. We use a script wrapper to deal with changing
# to the proper directory and to keep some of these details out
# of this.
#
$output = array();
$retval = 0;
$result = exec("$TBSUEXEC_PATH $uid $unix_gid ".
"webkillbatchexp $exp_pid $exp_eid",
$output, $retval);
if ($retval && $retval != 1) {
echo "<br><br><h2>
Cancelation Failure($retval): Output as follows:
</h2>
<br>
<XMP>\n";
for ($i = 0; $i < count($output); $i++) {
echo "$output[$i]\n";
}
echo "</XMP>\n";
PAGEFOOTER();
die("");
}
echo "<br><br><h2>\n";
#
# Exit status 0 means cancelation was immediate.
# Exit status 1 means the experiment was running, and will terminate later.
#
if ($retval) {
echo "Cancelation has started<br><br>
You will be notified via email when the process has completed,
and you can reuse the experiment name.
This typically takes less than 5 minutes.
If you do not receive email notification within a reasonable
amount of time, please contact $TBMAILADDR.\n";
}
else {
echo "Batchmode Experiment $exp_eid in project $exp_pid has
been canceled!\n";
}
echo "</h2>\n";
#
# Standard Testbed Footer
#
PAGEFOOTER();
?>
......@@ -57,19 +57,6 @@ if ($expt_terminating) {
"experiment has been torn down.", 1);
}
#
# If this is a running batch mode experiment, then force user through the
# terminate batchmode path, to ensure that this is really what the person
# wanted to do. Its also easier for me.
#
$batchmode = $row[batchmode];
if ($batchmode) {
USERERROR("The experiment $exp_eid is a batch mode experiment that ".
"is currently running on the testbed. If you really want to ".
"terminate this experiment, please go back and terminate it ".
"using the entry in the batch mode experiments listing.", 1);
}
#
# Verify permissions.
#
......@@ -137,7 +124,7 @@ $retval = 0;
$result = exec("$TBSUEXEC_PATH $uid $unix_gid webendexp $exp_pid $exp_eid",
$output, $retval);
if ($retval) {
if ($retval < 0) {
echo "<br><br><h2>
Termination Failure($retval): Output as follows:
</h2>
......@@ -152,15 +139,25 @@ if ($retval) {
die("");
}
echo "<br><br>";
echo "<h3>
Experiment `$exp_eid' in project `$exp_pid' is terminating!<br><br>
You will be notified via email when the experiment has been torn
down, and you can reuse the experiment name.
This typically takes less than 5 minutes.
If you do not receive email notification within a reasonable amount
of time, please contact $TBMAILADDR.
</h3>\n";
#
# Exit status 1 means termination/cancelation was immediate.
# Exit status 0 means the experiment is terminating, or will be.
#
echo "<br><br><h3>\n";
if ($retval) {
echo "Experiment `$exp_eid' in project `$exp_pid' has been terminated!
<br><br>
You may now reuse the experiment name.\n";
}
else {
echo "Experiment `$exp_eid' in project `$exp_pid' is terminating!<br><br>
You will be notified via email when the experiment has been torn
down, and you can reuse the experiment name.
This typically takes less than 5 minutes.
If you do not receive email notification within a reasonable amount
of time, please contact $TBMAILADDR.\n";
}
echo "</h3>\n";
#
# Standard Testbed Footer
......
<?php
include("defs.php3");
include("showstuff.php3");
#
# Standard Testbed Header
#
PAGEHEADER("Batch Mode Experiment Information");
#
# Only known and logged in users can end experiments.
#
$uid = GETLOGIN();
LOGGEDINORDIE($uid);
$isadmin = ISADMIN($uid);
#
# Verify page arguments.
#
if (!isset($eid) ||
strcmp($eid, "") == 0) {
USERERROR("You must provide an Experiment ID.", 1);
}
if (!isset($pid) ||
strcmp($pid, "") == 0) {
USERERROR("You must provide a Project ID.", 1);
}
$exp_eid = $eid;
$exp_pid = $pid;
#
# Check to make sure thats this is a valid PID/EID tuple.
#
$query_result =
DBQueryFatal("SELECT * FROM batch_experiments WHERE ".
"eid='$exp_eid' and pid='$exp_pid'");
if (mysql_num_rows($query_result) == 0) {
USERERROR("The experiment $exp_eid is not a valid batch mode experiment ".
"in project $exp_pid.", 1);
}
$exprow = mysql_fetch_array($query_result);
#
# Verify that this uid is a member of the project for the experiment
# being displayed.
#
if (!$isadmin) {
$query_result =
DBQueryFatal("SELECT pid FROM group_membership WHERE ".
"uid='$uid' and pid='$exp_pid'");
if (mysql_num_rows($query_result) == 0) {
USERERROR("You are not a member of Project $exp_pid for ".
"Experiment: $exp_eid.", 1);
}
}
$created = $exprow[created];
$expires = $exprow[expires];
$longname = $exprow[name];
$creator = $exprow[creator_uid];
$status = $exprow[status];
$attempts = $exprow[attempts];
#
# Generate the table.
#
echo "<table align=center border=1>\n";
echo "<tr>
<td>Name: </td>
<td class=\"left\">$exp_eid</td>
</tr>\n";
echo "<tr>
<td>Long Name: </td>
<td class=\"left\">$longname</td>
</tr>\n";
echo "<tr>
<td>Project: </td>
<td class=left>
<A href='showproject.php3?pid=$exp_pid'>$exp_pid</A></td>
</tr>\n";
echo "<tr>
<td>Experiment Head: </td>