#!/usr/bin/perl -wT # # Copyright (c) 2000-2008 University of Utah and the Flux Group. # # {{{EMULAB-LICENSE # # This file is part of the Emulab network testbed software. # # This file is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or (at # your option) any later version. # # This file is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public # License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this file. If not, see . # # }}} # use strict; use English; use Getopt::Std; # # This gets invoked from the Web interface and from idlemail # sub usage() { print STDOUT "Usage: idleswap [-i | -a] \n"; exit(-1); } # Hidden switch: -r = root mode - used by idlemail my $optlist = "iar"; my $idleswap = 0; my $autoswap = 0; my $rootokay = 0; # # Configure variables # my $TB = "@prefix@"; my $DBNAME = "@TBDBNAME@"; my $TBOPS = "@TBOPSEMAIL@"; my $TBLOGS = "@TBLOGSEMAIL@"; my $TBAUDIT = "@TBAUDITEMAIL@"; my $swapexp = "$TB/bin/swapexp"; my $template_swapout = "$TB/bin/template_swapout"; my $cleanupslice = "$TB/sbin/cleanupslice"; # Testbed Support libraries use lib "@prefix@/lib"; use libdb; use libtestbed; use Template; use Experiment; # Protos. sub fatal($); # Untaint the path $ENV{'PATH'} = '/bin:/usr/bin'; delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; # Turn off line buffering on output $| = 1; # We don't want to run this script unless its the real version. if ($EUID != 0) { fatal("Must be root! Maybe its a development version?"); } # Parse command arguments. Once we return from getopts, all that should # left are the required arguments. my %options = (); if (! getopts($optlist, \%options)) { usage(); } if (defined($options{"i"})) { $idleswap = 1; } if (defined($options{"a"})) { $autoswap = 1; } if (defined($options{"r"})) { $rootokay = 1; } # This script is setuid, so please do not run it as root. Hard to track # what has happened. if ($UID == 0 && (!defined($rootokay) || !$rootokay) ) { fatal("Please do not run this as root! Its already setuid!"); } if (@ARGV != 1) { usage(); } # # Verify user and get his DB uid and other info for later. # my $this_user = User->ThisUser(); if (!defined($this_user) && !$rootokay) { fatal("You ($UID) do not exist!"); } # # Grab the Experiment # my $experiment = Experiment->Lookup($ARGV[0]); if (! defined($experiment)) { fatal("No such experiment in the Emulab Database."); } my $pid = $experiment->pid(); my $eid = $experiment->eid(); # Need the swapper for below. my $swapper = $experiment->GetSwapper(); if (! defined($swapper)) { fatal("Could not get object for swapper."); } # Only admins or root can forcibly swap an idle experiment out. if (! TBAdmin() && ($UID!=0 || !$rootokay) ) { fatal("Only testbed administrators can issue a forcible swap!"); } # Flip to the user to do the swap. if ($swapper->FlipTo($experiment->unix_gid()) != 0) { fatal("Could not flip to $swapper"); } if ($experiment->IsInstance()) { my $instance = Template::Instance->LookupByExptidx($experiment->idx()); my $guid = $instance->guid(); my $vers = $instance->vers(); exec "$template_swapout -e $eid $guid/$vers"; die("Failed to exec $template_swapout!"); } elsif ($experiment->geniflags()) { my $uuid = $experiment->uuid(); exec "$cleanupslice $uuid"; die("Failed to exec $cleanupslice!"); } else { my $arg = ""; if ($idleswap) { $arg = "-i"; } elsif ($autoswap) { $arg = "-a"; } else { $arg = "-f"; } exec "$swapexp $arg -s out $pid $eid"; die("Failed to exec $swapexp!"); } exit(-1); sub fatal($) { my ($msg) = @_; die("*** $0:\n". " $msg\n"); }