From 87dd2e609226c648ca82e6bc04e043e225f6ba04 Mon Sep 17 00:00:00 2001 From: "Leigh B. Stoller" <stoller@flux.utah.edu> Date: Thu, 16 Dec 2004 16:07:54 +0000 Subject: [PATCH] The panic button ... * tbsetup/panic.in: New backend script to implement the panic button feature. When used, it will cut the severe the connection to the firewall node by using snmpit to disable the port. Sets the panic bit (and date) in the experiments table, and changes the state of the experiment from "active" to "paniced" to ensure that the experiment cannot be messed with (swapped out or modified). Sends email to tbops when the panic button is pressed. Used with -r option, reverses the above. State is set back to active, the panic bit is cleared, and the port is renabled with snmpit. * tbsetup/tbswap.in: During swapout, a firewalled experiment that has been paniced will get a cleaning; The nodes are powered off, then the osids for all the nodes are reset (with os_select) so that they will boot the MFS, and then the nodes are powered on. Then the control network is turned back on, and then I wait for the nodes to reboot (this is simply cause we do not record in the DB that a node is turned off, and if I do not wait, the reload daemon will end hitting the power button again if they do not reboot in time. We can fix this later. I am not planning to apply this to general firewalled experiments yet as the power cycling is going to be hard on the nodes, so would rather that we at least have a 1/2 baked plan before we do that. * www/showexp.php3: If experiment is firewalled, show the Panic Button, linked to the panic button web script. If the experiment has already had the panic button pressed, show a big warning message and explain that user must talk to tbops to swap the experiment out. Also fiddle with menu options so that the terminate link is gone, and the swap link is visible only in admin mode. In other words, only an admin person can swap an experiment once it is paniced. And of course, an admin person can the backend panic script above with the -r option, but thats not something to be done lightly. * db/libdb.pm.in: Add "paniced" as an experiment state (EXPTSTATE_PANICED). Add utility functions: TBExptSetPanicBit(), TBExptGetPanicBit(), and TBExptClearPanicBit(). * tbsetup/swapexp.in: Minor state fiddling so that an experiment can be swapped while in paniced state, but only when in admin mode. Also clear the panic bit when experiment is swapped out. * www/dbdefs.php3.in: Add "paniced" as an experiment state. Add a utility function TBExptFirewall() to see if experiment is firewalled. * www/panicbutton.php3: New web script to invoke the backend panic script mentioned above, after the usual confirm song and dance. * www/panicbutton.gif: New gif of a red panic button that I stole off the net. If anyone has sees/has a better one, feel free to replace this one. * utils/node_statewait.in: Add -s option so that I can pass in the state I want to wait for (used from tbswap above to wait for nodes to reach ISUP after power on). --- configure | 1 + configure.in | 1 + db/libdb.pm.in | 45 ++++++- tbsetup/GNUmakefile.in | 4 +- tbsetup/panic.in | 283 ++++++++++++++++++++++++++++++++++++++++ tbsetup/swapexp.in | 29 +++- tbsetup/tbswap.in | 98 +++++++++++++- tbsetup/webpanic.in | 24 ++++ utils/node_statewait.in | 11 +- www/dbdefs.php3.in | 20 +++ www/panicbutton.gif | Bin 0 -> 6073 bytes www/panicbutton.php3 | 142 ++++++++++++++++++++ www/showexp.php3 | 42 +++++- 13 files changed, 682 insertions(+), 18 deletions(-) create mode 100755 tbsetup/panic.in create mode 100644 tbsetup/webpanic.in create mode 100644 www/panicbutton.gif create mode 100644 www/panicbutton.php3 diff --git a/configure b/configure index d4a4436e80..2f23a414ec 100755 --- a/configure +++ b/configure @@ -1542,6 +1542,7 @@ outfiles="$outfiles Makeconf GNUmakefile \ tbsetup/plab/plabdiscover tbsetup/plab/etc/netbed_files/GNUmakefile \ tbsetup/ipassign/GNUmakefile tbsetup/ipassign/src/GNUmakefile \ tbsetup/ipassign/ipassign_wrapper tbsetup/assign_prepass \ + tbsetup/panic tbsetup/webpanic \ tip/GNUmakefile \ tmcd/GNUmakefile tmcd/tmcd.restart \ tmcd/common/GNUmakefile tmcd/common/config/GNUmakefile \ diff --git a/configure.in b/configure.in index 69a3a087ce..899e6f5e2e 100755 --- a/configure.in +++ b/configure.in @@ -572,6 +572,7 @@ outfiles="$outfiles Makeconf GNUmakefile \ tbsetup/plab/plabdiscover tbsetup/plab/etc/netbed_files/GNUmakefile \ tbsetup/ipassign/GNUmakefile tbsetup/ipassign/src/GNUmakefile \ tbsetup/ipassign/ipassign_wrapper tbsetup/assign_prepass \ + tbsetup/panic tbsetup/webpanic \ tip/GNUmakefile \ tmcd/GNUmakefile tmcd/tmcd.restart \ tmcd/common/GNUmakefile tmcd/common/config/GNUmakefile \ diff --git a/db/libdb.pm.in b/db/libdb.pm.in index 104dfd32b9..a5bd8e1601 100644 --- a/db/libdb.pm.in +++ b/db/libdb.pm.in @@ -67,7 +67,7 @@ use vars qw(@ISA @EXPORT); DBLIMIT_NSFILESIZE NODERELOADPENDING_EID EXPTSTATE_NEW EXPTSTATE_PRERUN EXPTSTATE_SWAPPED EXPTSTATE_SWAPPING - EXPTSTATE_ACTIVATING EXPTSTATE_ACTIVE + EXPTSTATE_ACTIVATING EXPTSTATE_ACTIVE EXPTSTATE_PANICED EXPTSTATE_TERMINATING EXPTSTATE_TERMINATED EXPTSTATE_QUEUED EXPTSTATE_MODIFY_PARSE EXPTSTATE_MODIFY_REPARSE EXPTSTATE_MODIFY_RESWAP EXPTSTATE_RESTARTING @@ -200,6 +200,8 @@ use vars qw(@ISA @EXPORT); TBExptMinMaxNodes TBExptSecurityLevel TBExptIDX TBDB_SECLEVEL_GREEN TBDB_SECLEVEL_YELLOW TBDB_SECLEVEL_ORANGE TBDB_SECLEVEL_RED + + TBExptSetPanicBit TBExptGetPanicBit TBExptClearPanicBit ); # Must come after package declaration! @@ -336,6 +338,7 @@ sub EXPTSTATE_QUEUED() { "queued"; } sub EXPTSTATE_SWAPPING() { "swapping"; } sub EXPTSTATE_ACTIVATING() { "activating"; } sub EXPTSTATE_ACTIVE() { "active"; } +sub EXPTSTATE_PANICED() { "paniced"; } sub EXPTSTATE_TERMINATING() { "terminating"; } sub EXPTSTATE_TERMINATED() { "ended"; } sub EXPTSTATE_MODIFY_PARSE() { "modify_parse"; } @@ -3776,6 +3779,46 @@ sub TBNodeFirewall ($$$) { return 1; } +# +# Set the paniced bit for an experiment. +# +sub TBExptSetPanicBit($$) { + my ($pid, $eid) = @_; + + return DBQueryWarn("update experiments set ". + " paniced=1,panic_date=now() ". + "where pid='$pid' and eid='$eid'"); +} + +# +# Clear the panic bit. +# +sub TBExptClearPanicBit($$) { + my ($pid, $eid) = @_; + + return DBQueryWarn("update experiments set ". + " paniced=0,panic_date=NULL ". + "where pid='$pid' and eid='$eid'"); +} + +# +# Get the value of the paniced bit. +# +sub TBExptGetPanicBit($$$) { + my ($pid, $eid, $panicp) = @_; + + my $query_result = + DBQueryWarn("select paniced,panic_date from experiments ". + "where pid='$pid' and eid='$eid'"); + if (!$query_result || $query_result->num_rows == 0) { + return 0; + } + my @row = $query_result->fetchrow_array(); + $$panicp = $row[0]; + + return 1; +} + # # Issue a DB query. Argument is a string. Returns the actual query object, so # it is up to the caller to test it. I would not for one moment view this diff --git a/tbsetup/GNUmakefile.in b/tbsetup/GNUmakefile.in index 0b7c379051..4085da3be3 100644 --- a/tbsetup/GNUmakefile.in +++ b/tbsetup/GNUmakefile.in @@ -28,14 +28,14 @@ SBIN_STUFF = resetvlans console_setup.proxy sched_reload named_setup \ exports_setup.proxy vnode_setup eventsys_start \ sfskey_update sfskey_update.proxy rmuser idleswap \ newnode_reboot savelogs.proxy eventsys.proxy \ - elabinelab snmpit.proxy + elabinelab snmpit.proxy panic CTRLBIN_STUFF = console_setup.proxy exports_setup.proxy sfskey_update.proxy \ savelogs.proxy eventsys.proxy LIBEXEC_STUFF = rmproj wanlinksolve wanlinkinfo \ os_setup mkexpdir console_setup webnscheck webreport \ - webendexp webbatchexp \ + webendexp webbatchexp webpanic \ assign_wrapper assign_prepass ptopgen webnodeupdate \ webdelay_config \ webrmgroup webswapexp webnodecontrol \ diff --git a/tbsetup/panic.in b/tbsetup/panic.in new file mode 100755 index 0000000000..7fbd72a277 --- /dev/null +++ b/tbsetup/panic.in @@ -0,0 +1,283 @@ +#!/usr/bin/perl -wT + +# +# EMULAB-COPYRIGHT +# Copyright (c) 2000-2004 University of Utah and the Flux Group. +# All rights reserved. +# + +use English; +use Getopt::Std; +use POSIX qw(isatty setsid); + +# +# Press the panic button. Also invoked from web interface. +# +sub usage() +{ + print(STDERR + "Usage: panicbutton [-r] <pid> <eid>\n". + "switches and arguments:\n". + "-r - Reset panic state (admin people only)\n". + "<pid> - The project the experiment belongs to\n". + "<eid> - The experiment name (id)\n"); + exit(-1); +} +my $optlist = "r"; +my $reset = 0; + +sub Fatal($); + +# +# Exit codes are important; they tell the web page what has happened so +# it can say something useful to the user. Fatal errors are mostly done +# with die(), but expected errors use this routine. At some point we will +# use the DB to communicate the actual error. +# +# $status < 0 - Fatal error. Something went wrong we did not expect. +# $status = 0 - Termination is proceeding in the background. Notified later. +# $status > 0 - Expected error. User not allowed for some reason. +# +sub ExitWithStatus($$) +{ + my ($status, $message) = @_; + + if ($status < 0) { + die("*** $0:\n". + " $message\n"); + } + else { + print STDERR "$message\n"; + } + exit($status); +} + +# +# Configure variables +# +my $TB = "@prefix@"; +my $TBOPS = "@TBOPSEMAIL@"; + +# +# Testbed Support libraries +# +use lib "@prefix@/lib"; +use libdb; +use libtestbed; + +# Be careful not to exit on transient error; 0 means infinite retry. +$libdb::DBQUERY_MAXTRIES = 0; + +my $snmpit = "$TB/bin/snmpit"; +my $dbuid; +my $user_name; +my $user_email; + +# +# 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 +# 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{"r"})) { + $reset = 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"); +} + +# +# See if the experiment is firewalled. Error if not. +# +my $firewall; +my $firewalled = TBExptFirewall($pid, $eid, \$firewall); + +if (!$firewalled) { + die("*** $0:\n". + " Experiment $pid/$eid is not firewalled!\n"); +} + +# +# Verify user and get his DB uid. +# +if (! UNIX2DBUID($UID, \$dbuid)) { + die("*** $0:\n". + " You do not exist in the Emulab Database.\n"); +} + +# +# Get email info for user. +# +if (! UserDBInfo($dbuid, \$user_name, \$user_email)) { + die("*** $0:\n". + " Cannot determine your name and email address.\n"); +} + +# +# Verify that this person is allowed to press the panic button. +# Note that any script down the line has to do an admin check also. +# +if ($UID && !TBAdmin($UID) && + !TBExptAccessCheck($dbuid, $pid, $eid, TB_EXPT_MODIFY)) { + die("*** $0:\n". + " You do not have permission to end this experiment!\n"); +} + +# +# We have to protect against trying to end an experiment that is currently +# in the process of being terminated. We use a "wrapper" state (actually +# a timestamp so we can say when termination was requested) since +# terminating consists of a couple of different experiment states down inside +# the tb scripts. +# +DBQueryFatal("lock tables experiments write"); + +$query_result = + DBQueryFatal("SELECT * FROM experiments WHERE eid='$eid' and pid='$pid'"); + +if (! $query_result->numrows) { + die("*** $0:\n". + " No such experiment $pid/$eid exists!\n"); +} +my %hashrow = $query_result->fetchhash(); +my $expt_head_login = $hashrow{'expt_head_uid'}; +my $estate = $hashrow{'state'}; + +# +# Called from user (via web interface). +# +if ($reset) { + ExitWithStatus(1, "Experiment $pid/$eid is not paniced!\n") + if ($estate ne EXPTSTATE_PANICED); +} +else { + ExitWithStatus(1, "Experiment $pid/$eid is not active!\n") + if (! ($estate eq EXPTSTATE_ACTIVE || + $estate eq EXPTSTATE_ACTIVATING || + $estate eq EXPTSTATE_SWAPPING)); +} + +# +# Change experiment state and lock it. +# +TBLockExp($pid, $eid, ($reset ? EXPTSTATE_ACTIVE : EXPTSTATE_PANICED)); +DBQueryFatal("unlock tables"); + +# +# XXX - At this point a failure is going to leave things in an +# inconsistent state. Be sure to call fatal() only since we are +# going into the background, and we have to send email since no +# one is going to see printed error messages (output goes into the +# log file, which will be sent along in the email). +# + +# +# Get email address of the experiment head, which may be different than +# the person who is actually terminating the experiment, since its polite +# to let the original creator know whats going on. +# +my $expt_head_name; +my $expt_head_email; + +if (! UserDBInfo($expt_head_login, \$expt_head_name, \$expt_head_email)) { + print "*** WARNING: ". + "Could not determine name/email for $expt_head_login.\n"; + $expt_head_name = "TBOPS"; + $expt_head_email = $TBOPS; +} + +$query_result = + DBQueryFatal("select card1 from wires ". + "where node_id1='$firewall' AND type='Control'"); + +if (!$query_result->numrows) { + fatal("Could not determine firewall port for $pid/$eid!"); +} +my ($port) = $query_result->fetchrow_array(); + +# +# Call snmpit. +# +if ($reset) { + system("$snmpit -e ${firewall}:${port}"); + if ($?) { + fatal("snmpit exited with $?!"); + } + TBExptClearPanicBit($pid, $eid); + print "Panic situation has been cleared!\n"; +} +else { + system("$snmpit -d ${firewall}:${port}"); + if ($?) { + fatal("snmpit exited with $?!"); + } + TBExptSetPanicBit($pid, $eid); + print "Panic Button has been pressed!\n"; +} +TBUnLockExp($pid, $eid); + +# +# Send email notification to user *and* to tbops. +# +SENDMAIL("$user_name <$user_email>", + "Panic Button ". ($reset ? "Cleared" : "Pressed") . + " for Experiment $pid/$eid", + "$dbuid has " . ($reset ? "cleared" : "pressed") . + " the panic button for experiment $pid/$eid", + "$user_name <$user_email>", + "Cc: $expt_head_name <$expt_head_email>\n". + "Bcc: $TBOPS"); + +exit 0; + +sub fatal($) +{ + my($mesg) = $_[0]; + + # + # Send a message to the testbed list. Append the logfile. + # + SENDMAIL("$user_name <$user_email>", + "Panic Button Failure for Experiment $pid/$eid", + "$dbuid ". ($reset ? "cleared" : "pressed") . + " the panic button for experiment $pid/$eid,\n". + "BUT there was a failure!\n\n". + "$mesg\n", + "$user_name <$user_email>", + "Cc: $expt_head_name <$expt_head_email>\n". + "Bcc: $TBOPS"); + + die("*** $0:\n". + " $mesg\n"); +} diff --git a/tbsetup/swapexp.in b/tbsetup/swapexp.in index e97c403155..b5dcd1fa85 100644 --- a/tbsetup/swapexp.in +++ b/tbsetup/swapexp.in @@ -107,6 +107,7 @@ my @row; my $action; my $nextswapstate; my $termswapstate; +my $isadmin = 0; # # Untaint the path @@ -270,12 +271,13 @@ if (! UserDBInfo($dbuid, \$user_name, \$user_email)) { die("*** $0:\n". " Cannot determine your name and email address.\n"); } +$isadmin = TBAdmin($UID); # # Verify that this person can muck with the experiment. # Note that any script down the line has to do an admin check also. # -if ($UID && !TBAdmin($UID) && +if ($UID && !$isadmin && !TBExptAccessCheck($dbuid, $pid, $eid, TB_EXPT_DESTROY)) { die("*** $0:\n". " You do not have permission to swap or modify this experiment!\n"); @@ -470,6 +472,17 @@ else { "or modify the experiment.\n") if ($canceled); + # + # Cannot swapmod an active elabinelab experiment, yet. + # + ExitWithStatus(1, + "Experiment $pid/$eid is an active ElabInElab.\n". + "You cannot modify this type of experiment while it\n". + "is swapped in. We hope to support this soon.\n") + if ($inout eq "modify" && + ($elabinelab || defined($elabinelab_eid)) && + $estate ne EXPTSTATE_SWAPPED()); + # # Check the state for the various operations. # @@ -484,12 +497,25 @@ else { }; /^out$/i && do { if ($estate ne EXPTSTATE_ACTIVE() && + $estate ne EXPTSTATE_PANICED() && $estate ne EXPTSTATE_ACTIVATING()) { ExitWithStatus(1, "Experiment $pid/$eid is not swapped in ". "or activating!\n"); } + # + # Must be an admin person to swap out an experiment that + # has had its panic button pressed. + # + if ($estate eq EXPTSTATE_PANICED() && !$isadmin) { + ExitWithStatus(1, + "Experiment $pid/$eid had its panic ". + "button pressed!\n". + "Only a testbed administrator can swap ". + "this experiment out."); + } + if ($estate eq EXPTSTATE_ACTIVATING()) { # # All we can do is set the cancel flag and hope that @@ -743,6 +769,7 @@ if ($inout eq "out") { } SetExpState($pid, $eid, EXPTSTATE_SWAPPED) or fatal("Failed to set experiment state to " . EXPTSTATE_SWAPPED()); + TBExptClearPanicBit($pid, $eid); } elsif ($inout eq "in") { my $optarg = ""; diff --git a/tbsetup/tbswap.in b/tbsetup/tbswap.in index 802933d058..6ba9cb5f46 100644 --- a/tbsetup/tbswap.in +++ b/tbsetup/tbswap.in @@ -416,15 +416,98 @@ sub doSwapout($) { } if ($firewalled) { - # XXX put all nodes into admin mode - print STDERR "Confining firewalled nodes.\n"; - TBDebugTimeStamp("moving nodes to purgatory"); + # + # If the panic button was pressed, put all nodes into admin + # mode and power them off. After the firewall is torn down, + # we can power them back up. + # + my @nodes = ExpNodes($pid, $eid, 1); + my $ADMINOSID = TB_OSID_FREEBSD_MFS; + my $paniced; + + TBExptGetPanicBit($pid, $eid, \$paniced); + + if ($paniced) { + print STDERR "Powering down nodes.\n"; + TBDebugTimeStamp("Powering down nodes"); + + system("power off @nodes"); + if ($?) { + # + # If an error, cannot continue. Must leave firewall in + # place. + # + print STDERR "*** Failed to power nodes off! Stopping.\n"; + return 1; + } + + # + # XXX: node_admin should take a list of nodes, or pid,eid. + # Instead, call os_select directly for now. + # + # Clear any one-shot boots and partition boots. + # + print STDERR "Changing OSID to admin MFS.\n"; + TBDebugTimeStamp("Changing OSID to admin MFS"); + + # Order matters cause os_select sillyness. + if (system("os_select -c -1 @nodes") || + system("os_select -t $ADMINOSID @nodes") || + system("os_select -c @nodes")) { + + # + # If an error, cannot continue. Must leave firewall in + # place. + # + print STDERR "*** Failed to reset OSIDs! Stopping.\n"; + return 1; + } + + # + # Now we can power up the nodes again. + # + print STDERR "Powering up nodes.\n"; + TBDebugTimeStamp("Powering up nodes"); + + system("power on @nodes"); + if ($?) { + # + # If an error, cannot continue. Must leave firewall in + # place. Eventually, we can continue past this, if we + # know what nodes failed. But for now we have to do the + # ISUP test to make sure nodes really got into the MFS. + # + print STDERR "*** Failed to power on nodes! Stopping.\n"; + return 1; + } + } # # Once all nodes are safely in the admin MFS, we can take # down the firewall # doFW($pid, $eid, FWTEARDOWN); + + if ($paniced) { + # + # Now wait for ISUP. I do this here cause the reload daemon + # will power cycle the nodes again if its reboot fails, and + # that will happen if the nodes are not back into the MFS in + # time. THe right thing to do is to store the power state in + # the DB, and have the reload daemon turn the nodes back on. + # + print STDERR "Waiting for nodes to boot the MFS.\n"; + TBDebugTimeStamp("Waiting for nodes to boot the MFS"); + + system("node_statewait -s " . TBDB_NODESTATE_ISUP . " @nodes"); + if ($?) { + # + # Okay to continue; reload daemon will probably send + # email later when the reload fails. + # + print STDERR "*** Some nodes failed to reboot. Continuing\n"; + } + } } # @@ -1050,6 +1133,7 @@ sub doFW($$$) { # my $fwsetupstr1 = "snmpit $cnetstack -m $fwvlanname $portlist"; my $fwsetupstr2 = "snmpit $cnetstack -T $fwport $cnetvlanname $fwvlanname"; + my $fwtakedownstr0 = "snmpit $cnetstack -e $fwport"; my $fwtakedownstr1 = "snmpit $cnetstack -m $cnetvlanname $portlist"; my $fwtakedownstr2 = "snmpit $cnetstack -o $fwvlanname"; my $fwtakedownstr3 = "snmpit $cnetstack -U $fwport"; @@ -1102,8 +1186,14 @@ sub doFW($$$) { # Record VLAN info now that everything is done TBSetExptFirewallVlan($pid, $eid, $fwvid, $fwvlan); } else { - TBDebugTimeStamp("snmpit firewall teardown: VLAN"); + TBDebugTimeStamp("snmpit re-enable fw control port: $fwport"); my $failed = 0; + if (system($fwtakedownstr0)) { + print STDERR + "*** Could not re-enable firewall control port $fwport!\n"; + $failed = 1; + } + TBDebugTimeStamp("snmpit firewall teardown: VLAN"); if (system($fwtakedownstr1)) { print STDERR "*** Could not return $portlist to Control VLAN!\n"; diff --git a/tbsetup/webpanic.in b/tbsetup/webpanic.in new file mode 100644 index 0000000000..8797d5bf12 --- /dev/null +++ b/tbsetup/webpanic.in @@ -0,0 +1,24 @@ +#!/usr/bin/perl -w + +# +# EMULAB-COPYRIGHT +# Copyright (c) 2004 University of Utah and the Flux Group. +# All rights reserved. +# +use English; + +# +# This gets invoked from the Web interface. Simply a wrapper ... +# + +# +# Configure variables +# +my $TB = "@prefix@"; + +# +# Run the real thing, and never return. +# +exec "$TB/sbin/panic", @ARGV; + +die("webpanic: Could not exec panic: $!"); diff --git a/utils/node_statewait.in b/utils/node_statewait.in index 1c5b84a620..d6c0c70cf5 100644 --- a/utils/node_statewait.in +++ b/utils/node_statewait.in @@ -14,11 +14,13 @@ use Getopt::Std; # sub usage() { - print STDOUT "Usage: node_statewait [-t timeout] [-a] | [node ...]\n"; + print STDOUT + "Usage: node_statewait [-s state] [-t timeout] [-a] | [node ...]\n"; exit(-1); } -my $optlist = "at:"; +my $optlist = "at:s:"; my $timeout = 60 * 6; +my $state = TBDB_NODESTATE_PXEWAIT; # # Configure variables @@ -50,6 +52,9 @@ if (! getopts($optlist, \%options)) { if (defined($options{"t"})) { $timeout = $options{"t"}; } +if (defined($options{"s"})) { + $state = $options{"s"}; +} # # All testnodes, or just some nodes. @@ -90,7 +95,7 @@ foreach my $node (sort(@nodes)) { # # Skip if something failed earlier. # - if (!TBNodeStateWait($node, TBDB_NODESTATE_PXEWAIT, $waitstart, $timeout)) { + if (!TBNodeStateWait($node, $state, $waitstart, $timeout)) { print STDOUT "nodewait ($node): Success\n"; next; } diff --git a/www/dbdefs.php3.in b/www/dbdefs.php3.in index aa13afa1bb..e095d14905 100644 --- a/www/dbdefs.php3.in +++ b/www/dbdefs.php3.in @@ -130,6 +130,7 @@ $TB_EXPTSTATE_SWAPPING = "swapping"; $TB_EXPTSTATE_SWAPPED = "swapped"; $TB_EXPTSTATE_ACTIVATING = "activating"; $TB_EXPTSTATE_ACTIVE = "active"; +$TB_EXPTSTATE_PANICED = "paniced"; $TB_EXPTSTATE_QUEUED = "queued"; # Interfaces roles. @@ -1851,6 +1852,25 @@ function TBPlabAvail() { return $types; } +# +# Is an experiment firewalled. +# +function TBExptFirewall($pid, $eid) { + # + # Short form: is there a firewall? + # Only check the firewalls table so that we can be called for a swapped + # experiment (swapped experiments don't have reserved table info). + # + $query_result = + DBQueryWarn("SELECT eid FROM firewalls ". + "WHERE pid='$pid' and eid='$eid' ". + "AND type LIKE '%-vlan'"); + if (!$query_result || !mysql_num_rows($query_result)) + return 0; + + return 1; +} + # # DB Interface. # diff --git a/www/panicbutton.gif b/www/panicbutton.gif new file mode 100644 index 0000000000000000000000000000000000000000..ed8fa6488d2934ff40d15a176c21f0e4b8be8ab9 GIT binary patch literal 6073 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 literal 0 HcmV?d00001 diff --git a/www/panicbutton.php3 b/www/panicbutton.php3 new file mode 100644 index 0000000000..62da119287 --- /dev/null +++ b/www/panicbutton.php3 @@ -0,0 +1,142 @@ +<?php +# +# EMULAB-COPYRIGHT +# Copyright (c) 2000-2004 University of Utah and the Flux Group. +# All rights reserved. +# +include("defs.php3"); +include("showstuff.php3"); + +# +# Only known and logged in users. +# +$uid = GETLOGIN(); +LOGGEDINORDIE($uid); + +# +# Must provide the EID! +# +if (!isset($pid) || + strcmp($pid, "") == 0) { + USERERROR("The project ID was not provided!", 1); +} + +if (!isset($eid) || + strcmp($eid, "") == 0) { + USERERROR("The experiment ID was not provided!", 1); +} + +$exp_eid = $eid; +$exp_pid = $pid; + +# Canceled operation redirects back to showexp page. See below. +if ($canceled) { + header("Location: showexp.php3?pid=$pid&eid=$eid"); + return; +} + +# +# Standard Testbed Header, after checking for cancel above. +# +PAGEHEADER("Press the Panic Button!"); + +# +# Check to make sure thats this is a valid PID/EID, while getting the +# experiment GID. +# +if (! TBExptGroup($exp_pid, $exp_eid, $exp_gid)) { + USERERROR("The experiment $exp_eid is not a valid experiment ". + "in project $exp_pid.", 1); +} + +# +# Verify permissions. +# +if (! TBExptAccessCheck($uid, $exp_pid, $exp_eid, $TB_EXPT_MODIFY)) { + USERERROR("You do not have permission to press the panic button for ". + "experiment $exp_eid!", 1); +} + +echo "<font size=+2>Experiment <b>". + "<a href='showproject.php3?pid=$exp_pid'>$exp_pid</a>/". + "<a href='showexp.php3?pid=$exp_pid&eid=$exp_eid'>$exp_eid</a>". + "</b></font>\n"; + +# +# 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 redirect the +# browser back up a level. +# +if (!$confirmed) { + echo "<center><h2><br> + Are you <b>REALLY</b> + sure you want to press the panic button for Experiment '$exp_eid?' + </h2>\n"; + + SHOWEXP($exp_pid, $exp_eid, 1); + + echo "<form action='panicbutton.php3?pid=$exp_pid&eid=$exp_eid'". + "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 unix gid for the project for running the scripts below. +# Note usage of default group in project. +# +TBGroupUnixInfo($exp_pid, $exp_gid, $unix_gid, $unix_name); + +# +# We run a wrapper script that does all the work. +# +echo "<center><br>"; +echo "<h2>Pressing the panic button. Please wait a moment ... + </h2></center>"; + +flush(); + +# +# Run the backend script. +# +$retval = SUEXEC($uid, "$exp_pid,$unix_gid", "webpanic $exp_pid $exp_eid", + SUEXEC_ACTION_IGNORE); + +# +# Fatal Error. Report to the user, even though there is not much he can +# do with the error. Also reports to tbops. +# +if ($retval < 0) { + SUEXECERROR(SUEXEC_ACTION_DIE); + # + # Never returns ... + # + die(""); +} + +# +# Exit status >0 means the operation could not proceed. +# Exit status =0 means the experiment is terminating in the background. +# +echo "<br>\n"; +if ($retval) { + echo "<h3>Panic Button failure</h3>"; + echo "<blockquote><pre>$suexec_output<pre></blockquote>"; +} +else { + echo "<h3>The panic button has been pressed!</h3><br> + You will need to contact testbed operations to continue.\n"; +} + +# +# Standard Testbed Footer +# +PAGEFOOTER(); +?> diff --git a/www/showexp.php3 b/www/showexp.php3 index a0cdd5dd0c..c96856aa29 100644 --- a/www/showexp.php3 +++ b/www/showexp.php3 @@ -12,6 +12,7 @@ include("showstuff.php3"); # $uid = GETLOGIN(); LOGGEDINORDIE($uid); +$isadmin = ISADMIN($uid); # # Verify page arguments. @@ -59,7 +60,7 @@ if (! TBExptAccessCheck($uid, $exp_pid, $exp_eid, $TB_EXPT_READINFO)) { # $query_result = DBQueryFatal("select e.idx,e.state,e.batchmode,e.linktest_pid,". - " s.rsrcidx,r.wirelesslans ". + " e.paniced,e.panic_date,s.rsrcidx,r.wirelesslans ". " from experiments as e ". "left join experiment_stats as s on s.exptidx=e.idx ". "left join experiment_resources as r on s.rsrcidx=r.idx ". @@ -71,6 +72,8 @@ $rsrcidx = $row["rsrcidx"]; $isbatch = $row["batchmode"]; $wireless = $row["wirelesslans"]; $linktest_running = $row["linktest_pid"]; +$paniced = $row["paniced"]; +$panic_date = $row["panic_date"]; # # Get a list of node types and classes in this experiment @@ -132,7 +135,8 @@ if ($expstate) { WRITESUBMENUBUTTON("Swap Experiment In", "swapexp.php3?inout=in&pid=$exp_pid&eid=$exp_eid"); } - elseif ($expstate == $TB_EXPTSTATE_ACTIVE) { + elseif ($expstate == $TB_EXPTSTATE_ACTIVE || + ($expstate == $TB_EXPTSTATE_PANICED && $isadmin)) { WRITESUBMENUBUTTON("Swap Experiment Out", "swapexp.php3?inout=out&pid=$exp_pid&eid=$exp_eid"); } @@ -142,8 +146,10 @@ if ($expstate) { "&pid=$exp_pid&eid=$exp_eid"); } } - WRITESUBMENUBUTTON("Terminate Experiment", - "endexp.php3?pid=$exp_pid&eid=$exp_eid"); + if ($expstate != $TB_EXPTSTATE_PANICED) { + WRITESUBMENUBUTTON("Terminate Experiment", + "endexp.php3?pid=$exp_pid&eid=$exp_eid"); + } # Batch experiments can be modifed only when paused. if ($expstate == $TB_EXPTSTATE_SWAPPED || @@ -215,7 +221,7 @@ if ($types['garcia'] || $classes['sg']) { "moteleds.php3?pid=$exp_pid&eid=$exp_eid"); } -if (ISADMIN($uid)) { +if ($isadmin) { if ($expstate == $TB_EXPTSTATE_ACTIVE) { SUBMENUSECTION("Beta-Test Options"); WRITESUBMENUBUTTON("Restart Experiment", @@ -241,12 +247,34 @@ SUBMENUEND_2A(); echo "<br> <a href='shownsfile.php3?pid=$exp_pid&eid=$exp_eid'> <img border=1 alt='experiment vis' - src='showthumb.php3?idx=$rsrcidx'></a>\n"; + src='showthumb.php3?idx=$rsrcidx'></a>"; SUBMENUEND_2B(); SHOWEXP($exp_pid, $exp_eid); +if (TBExptFirewall($exp_pid, $exp_eid) && + ($expstate == $TB_EXPTSTATE_ACTIVE || + $expstate == $TB_EXPTSTATE_PANICED || + $expstate == $TB_EXPTSTATE_ACTIVATING || + $expstate == $TB_EXPTSTATE_SWAPPING)) { + echo "<center>\n"; + if ($paniced) { + echo "<br><font size=+1 color=red><blink>". + "Your experiment was cut off via the Panic Button on $panic_date!". + "<br>". + "You will need to contact testbed operations to make further ". + "changes (swap, terminate) to your experiment.</blink></font>"; + } + else { + echo "<br><a href='panicbutton.php3?pid=$exp_pid&eid=$exp_eid'> + <img border=1 alt='panic button' src='panicbutton.gif'></a>"; + echo "<br><font color=red size=+2>". + " Press the Panic Button to contain your experiment". + "</font>\n"; + } + echo "</center>\n"; +} SUBPAGEEND(); # @@ -254,7 +282,7 @@ SUBPAGEEND(); # SHOWNODES($exp_pid, $exp_eid, $sortby); -if (ISADMIN($uid)) { +if ($isadmin) { echo "<center> <h3>Experiment Stats</h3> </center>\n"; -- GitLab