Commit f870a7e9 authored by Leigh Stoller's avatar Leigh Stoller

Interface change:

	Usage: os_load [-s | -w] [-r] [-i <imageid>] <node> [node ...]
        Usage: sched_reload [-f | -p] [-r] [-i <imageid>] <node> [node ...]

The imageid is now an optional argument. After continually forgetting
what imageid to use, or just plain forgetting the argument, and having
it try to load imageid pc53 on pcXX, I decided this interface was
bogus. With now imageid, select the default imageid for each node
provided. This is actually convenient since you can load multiple
types of nodes in one shot.
parent 188b8732
......@@ -26,7 +26,7 @@ use Exporter;
SetNodeBootStatus OSFeatureSupported IsShelved NodeidToExp
UserDBInfo DBQuery DBQueryFatal DBQueryWarn DBWarn DBFatal
DBQuoteSpecial UNIX2DBUID ExpState SetExpState ProjLeader
ExpNodes DBDateTime
ExpNodes DBDateTime DefaultImageID
);
# Must come after package declaration!
......@@ -458,6 +458,29 @@ sub NodeidToExp ($$$) {
return 1;
}
#
# Get the default ImageID for a particular node, from the node_types table.
#
# usage: DefaultImageID(char *nodeid)
# returns imageid if the node is valid and has a default imageid.
# returns 0 if there are problems.
#
sub DefaultImageID ($) {
my($nodeid) = @_;
my $query_result =
DBQueryFatal("select imageid from node_types as t ".
"left join nodes as n on t.type=n.type ".
"where n.node_id='$nodeid'");
if (! $query_result->num_rows) {
return 0;
}
my @row = $query_result->fetchrow_array();
return $row[0];
}
#
# Map login (db uid) to a user_name and user_email.
#
......
......@@ -12,20 +12,19 @@ use Getopt::Std;
# which defines how/where to load, and what partitions are affected.
# The nodes and partitions tables are updated appropriately.
#
# usage: os_load [-s] <imageid> <node> [node ...]
# usage: os_load -l
#
sub usage()
{
print STDOUT "Usage: os_load [-sw] [-r] <imageid> <node> [node ...]\n".
"Use -s to setup reload only, but do not issue a reboot\n".
"Use -w to block waiting for nodes to finish reloading\n".
print STDOUT "Usage: os_load [-s | -w] [-r] [-i <imageid>] ".
"<node> [node ...]\n".
"Use -i to specify an imageid. Use node default otherwise.\n".
"Use -s to setup reload only, but do not issue a reboot.\n".
"Use -w to block waiting for nodes to finish reloading.\n".
" (-s and -w are mutually exclusive)\n".
"Use -l to get a list of images you are permitted to load\n" .
"Use -r to use Frisbee support instead of netdisk\n";
"Use -l to get a list of images you are permitted to load.\n" .
"Use -r to use Frisbee support instead of netdisk (experimental).\n";
exit(-1);
}
my $optlist = "sldwr";
my $optlist = "sldwri:";
#
# Configure variables
......@@ -33,6 +32,9 @@ my $optlist = "sldwr";
my $TB = "@prefix@";
my $TESTMODE = @TESTMODE@;
my $TBOPS = "@TBOPSEMAIL@";
my $BOSSADDR = "@BOSSNODE@";
my $USERADDR = "@USERNODE@";
#
# Max number of simultaneous loads. Will be better with Frisbee.
......@@ -46,16 +48,16 @@ use lib "@prefix@/lib";
use libdb;
use libtestbed;
my $BOSSADDR = "boss.emulab.net";
my $USERADDR = "users.emulab.net";
my $NETDISKOSID = "NETDISK-STD";
my $FRISBEEPATH = "boss.emulab.net:/tftpboot/pxeboot.frisbee";
my $FRISBEEPATH = "$BOSSADDR:/tftpboot/pxeboot.frisbee";
my $FRISBEELAUNCHER = "$TB/sbin/frisbeelauncher";
my $nodereboot = "$TB/bin/node_reboot";
my $ping = "/sbin/ping";
my $dbg = 0;
my @row;
my %imageid_row = ();
my $usedefault = 1;
my $imageid;
my %imageid_row;
my @nodes = ();
my $mereuser = 0;
my $setuponly = 0;
......@@ -82,7 +84,7 @@ if (defined($options{"l"})) {
dolisting();
exit(0);
}
if (@ARGV < 2) {
if (@ARGV < 1) {
usage();
}
if (defined($options{"s"})) {
......@@ -97,24 +99,27 @@ if (defined($options{"r"})) {
if ($waitmode && $setuponly) {
usage();
}
my $imageid = shift;
if (defined($options{"i"})) {
$imageid = $options{"i"};
$usedefault = 0;
#
# Untaint args.
#
if ($imageid =~ /^([-\@\w.\+]+)$/) {
$imageid = $1;
}
else {
die("Bad data in $imageid.");
if ($imageid =~ /^([-\@\w.\+]+)$/) {
$imageid = $1;
}
else {
die("*** Bad $imageid name.\n");
}
}
#
# Untaint nodes.
#
foreach my $node ( @ARGV ) {
if ($node =~ /^([-\@\w]+)$/) {
$node = $1;
}
else {
die("Bad node name: $node.");
die("*** Bad node name: $node.\n");
}
push(@nodes, $node);
......@@ -129,87 +134,109 @@ if ($UID && !TBAdmin($UID)) {
$mereuser = 1;
}
#
# Grab the imageid description from the DB. The permission check for this
# is that mere user can load an image from any project he/she is a member of,
# or any image that has a null pid field, since those are defined to be
# open to anyone.
#
$db_result = DBQueryFatal("select * from images where imageid='$imageid'");
if ($db_result->numrows < 1) {
die("No such imageid $imageid!");
}
%imageid_row = $db_result->fetchhash();
my $imagepid = 0;
if (defined($imageid_row{'pid'})) {
$imagepid = $imageid_row{'pid'};
}
if ($mereuser && $imagepid && !ProjMember($imagepid)) {
die("You do not have permission to load imageid $imageid!");
}
#
# Check to make sure that mere user is allowed to muck with nodes
#
if ($mereuser) {
foreach my $node (@nodes) {
if (! NodeAccessCheck(\$node)) {
die("You do not have permission to load images on $node\n");
die("You do not have permission to load images on $node.\n");
}
}
}
my $loadpart = $imageid_row{'loadpart'};
my $loadlen = $imageid_row{'loadlength'};
my $imagepath = $imageid_row{'path'};
my $defosid = $imageid_row{'default_osid'};
#
# 0 means load the entire disk.
# Grab the imageid description from the DB. The permission check for this
# is that mere user can load an image from any project he/she is a member of,
# or any image that has a null pid field, since those are defined to be
# open to anyone.
#
my $diskpart = "";
if ($loadpart) {
$diskpart = "wd0:s${loadpart}";
}
else {
$diskpart = "wd0";
}
if (defined($imageid)) {
my $db_result =
DBQueryFatal("select * from images where imageid='$imageid'");
if ($db_result->numrows < 1) {
die("*** No such imageid $imageid is defined in the DB!\n");
}
%imageid_row = $db_result->fetchhash();
#
# For now, all testbed default images from from paper and all pid specific
# images come from plastic:/proj.
#
my $cmdline = "";
if ($imagepid) {
if (! ($imagepath =~ /^\/proj\//)) {
die("Your image must reside in /proj\n");
my $imagepid = 0;
if (defined($imageid_row{'pid'})) {
$imagepid = $imageid_row{'pid'};
}
if ($mereuser && $imagepid && !ProjMember($imagepid)) {
die("*** You do not have permission to load imageid $imageid!\n");
}
$cmdline = "${USERADDR}:$imagepath $diskpart";
}
else {
$cmdline = "${BOSSADDR}:$imagepath $diskpart";
}
#
# Loop for each node.
#
foreach my $node (@nodes) {
my $pc = $node;
print STDOUT "Changing default OS for $pc to $defosid\n";
#
# Oh, I suppose it would be nice to do this just once per imageid,
# but that would be a pain. Not in the mood.
#
#
# Get default imageid for this node if none specified on comand line.
#
if ($usedefault) {
if (! ($imageid = DefaultImageID($node))) {
die("*** No default imageid is defined for $node!\n");
}
}
my $db_result =
DBQueryFatal("select * from images where imageid='$imageid'");
if ($db_result->numrows < 1) {
die("*** No such imageid $imageid is defined in the DB!\n");
}
%imageid_row = $db_result->fetchhash();
my $loadpart = $imageid_row{'loadpart'};
my $loadlen = $imageid_row{'loadlength'};
my $imagepath = $imageid_row{'path'};
my $defosid = $imageid_row{'default_osid'};
#
# 0 means load the entire disk.
#
my $diskpart = "";
if ($loadpart) {
$diskpart = "wd0:s${loadpart}";
}
else {
$diskpart = "wd0";
}
#
# For now, all testbed default images come from paper and all pid specific
# images come from plastic:/proj.
#
my $cmdline = "";
if (defined($imageid_row{'pid'})) {
if (! ($imagepath =~ /^\/proj\//)) {
die("*** Your image must reside in /proj\n");
}
$cmdline = "${USERADDR}:$imagepath $diskpart";
}
else {
$cmdline = "${BOSSADDR}:$imagepath $diskpart";
}
print STDOUT "Changing default OS for $node to $defosid\n";
if (!$TESTMODE) {
DBQueryFatal("update nodes set ".
"def_boot_osid='$defosid',def_boot_path='' ".
"where node_id='$pc'");
"where node_id='$node'");
}
# Put it in the current_reloads table so that nodes can find out which
# OS to load
# OS to load
DBQueryFatal("replace into current_reloads ".
"(node_id, image_id) values ('$pc', '$imageid')");
"(node_id, image_id) values ('$node', '$imageid')");
#
# Assign partition table entries for each partition in the image.
......@@ -230,26 +257,27 @@ foreach my $node (@nodes) {
DBQueryFatal("replace into partitions ".
"(partition, osid, node_id) ".
"values('$i', '$osid', '$pc')");
"values('$i', '$osid', '$node')");
}
else {
DBQueryFatal("delete from partitions ".
"where node_id='$pc' and partition='$i'");
"where node_id='$node' and partition='$i'");
}
}
print STDOUT "Setting up reload for $pc\n";
print STDOUT "Setting up reload for $node\n";
if (!$TESTMODE) {
if ($frisbee) {
DBQueryFatal("update nodes set ".
"next_pxe_boot_path='$FRISBEEPATH'" .
"where node_id='$pc'");
system "$FRISBEELAUNCHER $imageid" and die "Unable to launch frisbee daemon\n";
"where node_id='$node'");
system "$FRISBEELAUNCHER $imageid" and
die "*** Unable to launch frisbee daemon\n";
} else {
DBQueryFatal("update nodes set ".
"next_boot_osid='$NETDISKOSID',".
"next_boot_cmd_line='$cmdline' ".
"where node_id='$pc'");
"where node_id='$node'");
}
}
}
......
......@@ -8,17 +8,19 @@ use Getopt::Std;
# 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] <imageid> <node> [node ...]
# usage: sched_reload [-f | -p] [-r] [-i <imageid>] <node> [node ...]
#
sub usage()
{
print STDOUT "Usage: sched_reload [-f | -p] <imageid> <node> [node ...]\n".
"Use the -f to force reload. Fail if node cannot be reserved.\n".
"Use the -p to pend reload for the reload daemon.\n" .
"Use the -r use Frisbee rather than netdisk (experimental).\n";
print STDOUT "Usage: sched_reload [-f | -p] [-r] [-i <imageid>] ".
"<node> [node ...]\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 -r to use Frisbee rather than netdisk (experimental).\n";
exit(-1);
}
my $optlist = "fpr";
my $optlist = "fpri:";
#
# Configure variables
......@@ -47,6 +49,9 @@ my $force = 0;
my $pend = 0;
my $frisbee = 0;
my @nodes = ();
my $usedefault = 1;
my $imageid;
my %imagenodes = ();
my @row;
# un-taint path
......@@ -63,7 +68,7 @@ $| = 1; #Turn off line buffering on output
if (! getopts($optlist, \%options)) {
usage();
}
if (@ARGV < 2) {
if (@ARGV < 1) {
usage();
}
if (defined($options{"f"})) {
......@@ -79,10 +84,20 @@ if (defined($options{"r"})) {
if ($pend and $force) {
usage();
}
my $imageid = shift;
if (defined($options{"i"})) {
$imageid = $options{"i"};
$usedefault = 0;
if ($imageid =~ /^([-\@\w.\+]+)$/) {
$imageid = $1;
}
else {
die("Bad data in $imageid.");
}
}
# This type will be put into the database, to allow programs
# such as nfree to figure out what kind of reload is support
# such as nfree to figure out what kind of reload is supposed
# to occur
if ($frisbee) {
$type = "frisbee";
......@@ -91,15 +106,8 @@ if ($frisbee) {
}
#
# Untaint args.
# Untaint nodes.
#
if ($imageid =~ /^([-\@\w.\+]+)$/) {
$imageid = $1;
}
else {
die("Bad data in $imageid.");
}
foreach my $node ( @ARGV ) {
if ($node =~ /^([-\@\w]+)$/) {
$node = $1;
......@@ -120,13 +128,16 @@ if ($UID && !TBAdmin($UID)) {
}
#
# Confirm a valid imageid!
# Confirm a valid imageid if one was specified. Otherwise we are going
# to pull it out of the DB for each node.
#
my $query_result =
DBQueryFatal("select * from images where imageid='$imageid'");
if (defined($imageid)) {
my $query_result =
DBQueryFatal("select * from images where imageid='$imageid'");
if ($query_result->numrows < 1) {
die("*** No such imageid $imageid is registered in the DB!");
if ($query_result->numrows < 1) {
die("*** No such imageid $imageid is registered in the DB!");
}
}
#
......@@ -142,6 +153,15 @@ foreach my $node (@nodes) {
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("*** No default imageid is defined for $node!\n");
}
}
print STDERR "Checking if $pc is reserved...";
$sth = DBQueryFatal("select * from reserved where node_id='$pc'");
......@@ -165,7 +185,6 @@ foreach my $node (@nodes) {
# won't be fooled into thinking a reload is required.
#
DBQueryFatal("delete from last_reservation where node_id='$pc'");
push (@load_list,$pc);
$allocated = 1;
}
} else {
......@@ -185,21 +204,46 @@ foreach my $node (@nodes) {
DBQueryFatal("replace into scheduled_reloads ".
"(node_id, image_id, reload_type) values ".
"('$pc', '$imageid','$type')");
#
# 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!\n";
print STDOUT "Reload Scheduling Done! There were $error failures!\n";
exit $error;
}
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";
}
#
# 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 -i $id @nodelist";
print "Issuing $cmd\n";
if (system($cmd)) {
print STDERR "*** WARNING: Failed $cmd\n";
$error++;
}
}
print STDOUT "Reload Scheduling Done!\n";
print STDOUT "Reload Scheduling Done! There were $error failures!\n";
exit $error;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment