Commit a37f936b authored by Gary Wong's avatar Gary Wong

Make emulabserver's node.getlist() aware of reservations.

(Along the way, adding an option to "predict" to compute the minimum free
node count over a type period.)

Closes #373.
parent cfb9f9e1
......@@ -47,12 +47,15 @@ sub usage()
print STDERR "Usage: predict [-p] [-u] [-t time] type\n";
print STDERR " predict -c type [pid...]\n";
print STDERR " predict -l type [pid...]\n";
print STDERR " predict -n [-t time] [-D duration] type [pid...]\n";
print STDERR " predict -P type [pid...]\n";
print STDERR " predict -x [-T type] pid...\n";
print STDERR " -h This message\n";
print STDERR " -c Give an oversimplified free node count\n";
print STDERR " -l Give a list of node allocation status counts " .
"over time\n";
print STDERR " -n Compute the minimum free pool size over a time " .
"period\n";
print STDERR " -P Identify periods of node pressure\n";
print STDERR " -x Show earliest unfulfilled reservation\n";
print STDERR " -p Identify by pid only, not pid/eid\n";
......@@ -62,9 +65,11 @@ sub usage()
exit( -1 );
}
my $optlist = "cdhlpPt:T:x";
my $optlist = "cdD:hlnpPt:T:x";
my $debug = 0;
my $duration = 365 * 24 * 60 * 60; # default to 1 year ~= infinity
my $time = time; # default to now
my $minfree = 0;
my $pidonly = 0;
my $countonly = 0;
my $pressure = 0;
......@@ -126,6 +131,13 @@ if (defined($options{"t"})) {
}
}
}
if (defined($options{"D"})) {
$duration = $options{"D"};
if ($duration !~ /^\d+$/) {
fatal("Could not parse -D option.");
}
$duration *= 60 * 60;
}
if (defined($options{T})) {
$type = $options{T};
}
......@@ -135,10 +147,14 @@ if (defined($options{"c"})) {
if (defined($options{"l"})) {
$timeseries = 1;
}
if (defined($options{"n"})) {
$minfree = 1;
}
if (defined($options{"x"})) {
$unfulfilled = 1;
}
usage() if( ( $countonly || $timeseries || $pressure || $unfulfilled ) ?
usage() if( ( $countonly || $timeseries || $pressure || $unfulfilled ||
$minfree ) ?
@ARGV < 1 : @ARGV != 1 );
if( !$unfulfilled ) {
$type = shift( @ARGV );
......@@ -153,6 +169,29 @@ if( $countonly ) {
exit( 0 );
}
if( $minfree ) {
my $min = 0xFFFF;
foreach my $rec ( Reservation->Forecast( $type, \@ARGV ) ) {
my $sample = $rec->{'held'} + $rec->{'free'};
if( $rec->{'t'} < $time ) {
# record is before period of interest; retain only the
# newest available
$min = $sample;
} elsif( $rec->{'t'} <= $time + $duration ) {
# record is during period of interest; compute the minimum
$min = $sample if( $sample < $min );
} else {
# we've gone past the end of the period and no longer care
# about the future
last;
}
}
print "$min\n";
exit( 0 );
}
if( $timeseries ) {
print "Time Unavailable Held Free\n";
print "---------- ----- ---- ----\n";
......
......@@ -39,6 +39,7 @@ import signal
import types
import datetime
import syslog
import subprocess
# Configure variables
TBDIR = "@prefix@"
......@@ -49,6 +50,7 @@ USERNODE = "@USERNODE@"
BASEADDR = "@FRISEBEEMCASTADDR@"
BASEPORT = "@FRISEBEEMCASTPORT@"
SUBBOSS_UID = "elabman"
PREDICT = "@prefix@/sbin/predict"
TBPATH = os.path.join(TBDIR, "lib")
if TBPATH not in sys.path:
......@@ -3432,13 +3434,44 @@ class node:
result = {}
pass
else:
# compute the set of types in the result list, because
# we'll want to run reservation admission control against
# each type
freecounts = {}
for row in res:
freecounts[ row[ 1 ] ] = 0
predict_cmd = [ PREDICT ]
if argdict.has_key( "start" ):
if not re.match( "^[-:0-9 ]+*$", str( argdict[ "start" ] ) ):
return EmulabResponse( RESPONSE_BADARGS,
output="Bad chars in start time" )
predict_cmd.append( "-t " + argdict[ "start" ] )
if argdict.has_key( "duration" ):
if not re.match( "^[0-9]+*$", str( argdict[ "duration" ] ) ):
return EmulabResponse( RESPONSE_BADARGS,
output="Bad chars in duration" )
dur_arg = "-D " + argdict[ "duration" ] + " "
else:
# use 75 hours if not specified, since that's the CHPC default
dur_arg = "-D 75 "
predict_cmd.append( dur_arg )
for t in freecounts:
freecounts[ t ] = int( subprocess.check_output( predict_cmd + [ t ] ) )
result = {}
# gotta enumerate the list of nodes of this type that are avail
for row in res:
avail = freecounts[ row[ 1 ] ] > 0
result[row[0]] = {
"node_id" : row[0],
"type" : row[1],
"free" : (row[2] == 1 and row[3] == 1 and row[8] == 1),
"free" : (avail and row[2] == 1 and row[3] == 1 and
row[8] == 1),
}
if row[4]:
result[row[0]]["site"] = row[4]
......@@ -3452,6 +3485,8 @@ class node:
if row[7] and row[7] != "":
result[row[0]]["hostname"] = row[7]
pass
if avail:
freecounts[ row[ 1 ] ] -= 1
pass
pass
......
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