#!/usr/bin/perl -wT use English; use Getopt::Std; # # Schedule the reloading of a disk partition on a node. If the node is # currently not reserved, start the loading now after reserving it to # testbed:reloading. Otherwise, put the right info into the database, and # nfree will do it when the node gets freed. # # usage: sched_reload [-f | -p] [-r|-n] [-i ] [node ...] # sub usage() { print STDOUT "Usage: sched_reload [-f | -p] [-r | -n] [-i ] ". " [node ...]\n". " sched_reload -e pid,eid\n". "Use -i to specify an imageid. Use node default otherwise.\n". "Use -f to force reload. Fail if node cannot be reserved.\n". "Use -p to pend reload for the reload daemon.\n". "Use -e to schedule a reload for all nodes in an experiment.\n". "Use -r to use Frisbee for reloading disks.\n" . "Use -n to use netdisk for reloading disks.\n"; exit(-1); } my $optlist = "fprni:e:"; # # Configure variables # my $TB = "@prefix@"; # # Load the Testbed support stuff. # use lib "@prefix@/lib"; use libdb; # # These come from the library. # my $RELOADPID = NODERELOADING_PID; my $RELOADEID = NODERELOADING_EID; my $PENDINGEID = NODERELOADPENDING_EID; my $osload = "$TB/bin/os_load"; my $nalloc = "$TB/bin/nalloc"; my $name = ""; my $error = 0; my $debug = 0; my $force = 0; my $pend = 0; my $type = TB_DEFAULT_RELOADTYPE; my @nodes = (); my $usedefault = 1; my $imageid; my %imagenodes = (); my @row; my $eidmode = 0; my $pid; my $eid; # un-taint path $ENV{'PATH'} = '/bin:/usr/bin:/usr/local/bin'; delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'}; $| = 1; #Turn off line buffering on output # # 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{"f"})) { $force = $options{"f"}; } if (defined($options{"p"})) { $pend = $options{"p"}; } if (defined($options{"r"})) { if (defined($options{"n"})) { die "Only one of -r or -n should be given\n"; } $type = TB_RELOADTYPE_FRISBEE; } if (defined($options{"n"})) { $type = TB_RELOADTYPE_NETDISK; } if ($pend and $force) { usage(); } if (defined($options{"i"})) { $imageid = $options{"i"}; $usedefault = 0; if ($imageid =~ /^([-\@\w.\+]+)$/) { $imageid = $1; } else { die("Bad data in $imageid."); } } if (defined($options{"e"})) { if (@ARGV) { usage(); } $eidmode = $options{"e"}; if ($eidmode =~ /([-\w]*),([-\w]*)/) { $pid = $1; $eid = $2; } else { print STDOUT "Invalid argument to -e option: $eidmode\n"; usage(); } } else { if (@ARGV < 1) { usage(); } } # # Depending on the reload type, we pass different flags to os_load # my $osload_flags = ""; if ($type eq TB_RELOADTYPE_NETDISK) { $osload_flags .= ' -n '; } elsif ($type eq TB_RELOADTYPE_FRISBEE) { $osload_flags .= ' -r '; } if ($eidmode) { if (! (@nodes = ExpNodes($pid, $eid))) { die("*** $0:\n". " There are no nodes allocated to experiment $pid/$eid!"); } } else { # # Untaint nodes. # foreach my $node ( @ARGV ) { if ($node =~ /^([-\@\w]+)$/) { $node = $1; } else { die("Bad node name: $node."); } push(@nodes, $node); } } # # Root and admin types can do whatever they want. # Mere users cannot schedule reloads. # if ($UID && !TBAdmin($UID)) { die("*** $0:\n". " Only root or TB administrators can schedule disk reloads.\n"); } # # Confirm a valid imageid if one was specified. Otherwise we are going # to pull it out of the DB for each node. # if (defined($imageid)) { my $query_result = DBQueryFatal("select * from images where imageid='$imageid'"); if ($query_result->numrows < 1) { die("*** $0:\n". " No such imageid $imageid is registered in the DB!"); } } # # A loop. # my @load_list=(); foreach my $node (@nodes) { my $pc = $node; my $allocated = 0; $sth = DBQueryFatal("select * from nodes where node_id='$pc'"); if ($sth->num_rows() != 1) { print STDERR "Node $pc doesn't exist. Skipping $pc.\n"; next; } # # Get default imageid for this node if none specified on comand line. # if ($usedefault) { if (! ($imageid = DefaultImageID($node))) { die("*** $0:\n". " No default imageid is defined for $node!\n"); } } print STDERR "Checking if $pc is reserved..."; $sth = DBQueryFatal("select * from reserved where node_id='$pc'"); if ( ($sth->num_rows()) < 1) { print STDERR "Available.\nReserving and adding to list.\n"; my $eid; if ($pend) { $eid = $PENDINGEID; } else { $eid = $RELOADEID; } my $cmd = "$nalloc $RELOADPID $eid $pc"; if ( system($cmd) != 0 ) { print STDERR "WARNING: Could not reserve $pc!\n"; } else { # # Kill the last_reservation so that whoever gets the node next # won't be fooled into thinking a reload is required. # DBQueryFatal("delete from last_reservation where node_id='$pc'"); $allocated = 1; } } else { print STDERR "Reserved.\n"; } # # If force and not able to reserve, do not pend a reload. # if ($force && !$allocated) { $error++; next; } # Put it in the reloads table so TMCD knows to free it. if (! TBSetSchedReload($pc, $imageid, $type)) { die("*** $0:\n". " Could not set scheduled reload for $pc!"); } # # The point of this hash table is so that we can gather up all the # nodes per imageid and issue single requests to os_load, so that it # can optimize things (say, for Frisbee). It is possible to get multiple # imageids when using the node defaults instead of a command line imageid. # # Note that building up a hashed array of lists is a mighty odd operation # in PERL, hence this funny looking code! # if ($allocated) { if (! defined($imagenodes{$imageid})) { $imagenodes{$imageid} = [ $node ]; } else { push(@{ $imagenodes{$imageid} }, $node); } } } if ($pend) { print STDOUT "Reload Scheduling Done! There were $error failures!\n"; exit $error; } # # Now issue the reloads, one per imageid. The hash table we created above # stores a list of nodes for each imageid. # foreach my $id ( keys(%imagenodes) ) { my @nodelist = @{ $imagenodes{$imageid} }; my $cmd = "$osload $osload_flags -i $id @nodelist"; print "Issuing $cmd\n"; if (system($cmd)) { print STDERR "*** WARNING: Failed $cmd\n"; $error++; } } print STDOUT "Reload Scheduling Done! There were $error failures!\n"; exit $error;