#!/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] [node ...] # sub usage() { print STDOUT "Usage: sched_reload [-f] [node ...]\n". "Use the -f to force reload. Fail if node cannot be reserved.\n"; exit(-1); } my $optlist = "f"; # # Configure variables # my $TB = "@prefix@/bin"; my $DBNAME = "@TBDBNAME@"; my $osload = "$TB/os_load"; my $name = ""; my $mereuser = 0; my $error = 0; my $debug = 0; my $force = 0; my @nodes = (); my @row; # 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 (@ARGV < 2) { usage(); } if (defined($options{"f"})) { $force = $options{"f"}; } my $imageid = shift; # # Untaint args. # if ($imageid =~ /^([-\@\w.\+]+)$/) { $imageid = $1; } else { die("Bad data in $imageid."); } foreach my $node ( @ARGV ) { if ($node =~ /^([-\@\w]+)$/) { $node = $1; } else { die("Bad node name: $node."); } push(@nodes, $node); } # # Set up for querying the database. # use Mysql; my $DB = Mysql->connect("localhost", $DBNAME, "script", "none"); # # Figure out who called us. Root and admin types can do whatever they # want. Normal users can only change nodes in experiments in their # own projects. # if ($UID != 0) { ($name) = getpwuid($UID) or die "$UID not in passwd file\n"; $db_result = $DB->query("select admin from users where uid='$name'"); @row = $db_result->fetchrow_array(); if ($row[0] != 1) { $mereuser = 1; } } # # Mere Users cannot schedule reloads. # if ($mereuser) { die("Only root or TB administrators can schedule disk reloads.\n"); } # # A loop. # my @load_list=(); foreach my $node (@nodes) { my $pc = $node; $sth = $DB->query("select * from nodes where node_id='$pc'"); if ($sth == 0) { die("Database lookup failed (exists). Aborted...\n"); } if ($sth->num_rows() != 1) { print STDERR "Node $pc doesn't exist. Skipping $pc.\n"; next; } print STDERR "Checking if $pc is reserved..."; $sth = $DB->query("select * from reserved where node_id='$pc'"); if ($sth == 0) { die("Database lookup failed (reserved). Aborted...\n"); } my $allocated = 0; if ( ($sth->num_rows()) < 1) { print STDERR "Available.\nReserving and adding to list.\n"; # # XXX If you change testbed/reloading, be sure to update the # test in doreboot() in tmcd/tmcd.c. # my $cmd = "$TB/nalloc testbed reloading $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. # $sth = $DB->query("delete from last_reservation ". "where node_id='$pc'"); push (@load_list,$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. print STDERR "Scheduling reload of $imageid for $pc:\n"; $sth = $DB->query("replace into reloads ". "(node_id, image_id) values ('$pc', '$imageid')"); if ($sth == 0) { die("Database update failed (reloads). Aborted...\n"); } } if (@load_list > 0) { print STDERR "Running os_load on ",join(", ",@load_list),":\n"; $cmd = "$osload $imageid @load_list"; print STDERR "Calling '$cmd'\n"; if ( system($cmd) != 0 ) { print STDERR "WARNING: OS_LOAD FAILED ON @load_list!\n"; } } print STDOUT "Reload Scheduling Done!\n"; exit $error;