Commit 8b52132b authored by Leigh B Stoller's avatar Leigh B Stoller

First batch of changes to check to see if an extension is allowed, by

asking the reservation system at the remote cluster.
parent fd0df2ef
......@@ -96,7 +96,25 @@ sub Lookup($$)
my ($class, $token) = @_;
my $query_result;
if ($token =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/) {
if ($token =~ /^([-\w]*),([-\w]*)$/ ||
$token =~ /^([-\w]*)\/([-\w]*)$/) {
$query_result =
DBQueryWarn("select uuid from apt_instances ".
"where pid='$1' and name='$2'");
return undef
if (! (defined($query_result) && $query_result->numrows));
my ($uuid) = $query_result->fetchrow_array();
# Look in cache first
return $instances{$uuid}
if (exists($instances{$uuid}));
$query_result =
DBQueryWarn("select * from apt_instances where uuid='$uuid'");
}
elsif ($token =~ /^\w+\-\w+\-\w+\-\w+\-\w+$/) {
# Look in cache first
return $instances{$token}
if (exists($instances{$token}));
......@@ -2633,5 +2651,33 @@ sub OpenstackData($$)
return undef;
}
#
# Check to see if we can extend a slice.
#
sub CheckReservation($$)
{
my ($self, $new_expires) = @_;
my $authority = $self->GetGeniAuthority();
my $context = APT_Geni::RootContext();
my $slice = $self->instance()->GetGeniSlice();
return undef
if (! (defined($authority) && defined($context) &&
defined($slice)));
my $args = {
"slice_urn" => $slice->urn(),
"expiration" => $new_expires,
};
my $cmurl = $authority->url();
$cmurl =~ s/\/cm$/\/cluster/;
$cmurl = devurl($cmurl) if ($usemydevtree);
my $response = Genixmlrpc::CallMethod($cmurl, $context,
"SliceCheckReservation", $args);
return $response;
bad:
return undef;
}
# _Always_ make sure that this 1 is at the end of the file...
1;
......@@ -133,6 +133,8 @@ sub DoDeleteNodes();
sub DoUtilization();
sub DoIdleData();
sub DoOpenstack();
sub DoCheckReservation();
sub CheckReservationInternal($$$);
sub WriteCredentials();
sub StartMonitor();
sub StartMonitorInternal(;$@);
......@@ -246,6 +248,9 @@ elsif ($action eq "idledata") {
elsif ($action eq "openstackstats") {
DoOpenstack()
}
elsif ($action eq "checkreservation") {
DoCheckReservation()
}
else {
usage();
}
......@@ -1586,6 +1591,16 @@ sub ExtendInternal($$$$)
}
my $new_expires = $slice->ExpirationGMT();
#
# Do a reservation check first. We do not care if it fails (yet),
# just keep going.
#
if (CheckReservationInternal($slice, $new_expires, \$errmsg)) {
if ($debug) {
print "Reservation denied! $errmsg\n";
}
}
my $coderef = sub {
my ($sliver) = @_;
my $webtask = $sliver->webtask();
......@@ -1662,6 +1677,111 @@ sub ExtendInternal($$$$)
$$perrmsg = $errmsg;
return $errcode;
}
#
# Check with the reservation system.
#
sub DoCheckReservation()
{
my $slice = $instance->GetGeniSlice();
my $errmsg;
usage()
if (!@ARGV);
my $wanted = shift(@ARGV);
my $expiration = POSIX::strftime("20%y-%m-%d %H:%M:%S %Z",
localtime(str2time($slice->expires()) +
3600 * 24 * $wanted));
if ($slice->Lock()) {
print STDERR "Experiment is busy, cannot lock it. Try again later.\n";
exit(GENIRESPONSE_BUSY);
}
if (CheckReservationInternal($slice, $expiration, \$errmsg)) {
if ($debug) {
print "Reservation denied! $errmsg\n";
}
$slice->UnLock();
exit(1);
}
if ($debug) {
print "Reservation allowed!\n";
}
$slice->UnLock();
exit(0);
}
sub CheckReservationInternal($$$)
{
my ($slice, $expiration, $perrmsg) = @_;
my $errcode = -1;
my $errmsg;
my $coderef = sub {
my ($sliver) = @_;
my $webtask = $sliver->webtask();
my $domain = $sliver->domain();
my $errmsg;
return 0
if ($sliver->isAL2S());
my $response = $sliver->CheckReservation($expiration);
if (!defined($response)) {
$errmsg = "Internal error calling CheckReservation at $domain";
goto bad;
}
if ($response->code() != GENIRESPONSE_SUCCESS) {
$errmsg = "Failed to check reservation at $domain: ".
$response->output();
# This is something the user should see.
if ($response->code() == GENIRESPONSE_REFUSED ||
$response->code() == GENIRESPONSE_SERVER_UNAVAILABLE ||
$response->code() == GENIRESPONSE_BUSY) {
$webtask->output($errmsg);
$webtask->Exited($response->code());
return 1;
}
goto bad;
}
return 0;
bad:
print STDERR "$errmsg\n";
$webtask->output($errmsg);
$webtask->Exited(-1);
return -1;
};
my @return_codes = ();
my @agglist = $instance->AggregateList();
if (ParRun({"maxwaittime" => 99999,
"maxchildren" => scalar(@agglist)},
\@return_codes, $coderef, @agglist)) {
#
# The parent caught a signal. Leave things intact so that we can
# kill things cleanly later.
#
$errmsg = "Internal error calling Extend\n";
goto bad;
}
#
# Check the exit codes.
#
foreach my $agg (@agglist) {
my $code = shift(@return_codes);
if ($code) {
$agg->webtask()->Refresh();
$errmsg = $agg->webtask()->output();
$errcode = $agg->webtask()->exitcode();
goto bad;
}
}
return 0;
bad:
$$perrmsg = $errmsg;
return $errcode;
}
#
# Deny extension, sending optional email to user (which is also saved in
......@@ -3631,7 +3751,7 @@ sub DoSchedTerminate()
my $created = POSIX::strftime("20%y-%m-%d %H:%M:%S %Z",
localtime(str2time($instance->created())));
my $message = "The site administrator has scheduled this experiment\n".
"to terminate in $days days.";
($days ? "to terminate in $days days." : "for immediate termination!");
my $subject = "Experiment Termination Warning: $name";
#
......
......@@ -48,6 +48,7 @@ use GeniResponse;
use GeniSlice;
use GeniHRN;
use GeniUtil;
use Reservation;
use English;
use Data::Dumper;
use Date::Parse;
......@@ -500,5 +501,44 @@ sub SliceOpenstackData($)
return GeniResponse->Create(GENIRESPONSE_SUCCESS, $output);
}
#
# Check Reservation request for a slice.
#
sub SliceCheckReservation($)
{
my ($argref) = @_;
my $slice_urn = $argref->{'slice_urn'};
my $expiration= $argref->{'expiration'};
my %blob = ();
my $reserror;
my $hasperm = CheckPermission();
return $hasperm
if (GeniResponse::IsError($hasperm));
# Gack, why does Frontier do this. It is stupid.
if (ref($expiration) eq 'Frontier::RPC2::DateTime::ISO8601') {
$expiration = $expiration->value;
}
# Convert to a localtime.
$expiration = eval { timegm(strptime($expiration)); };
if ($@) {
return GeniResponse->Create(GENIRESPONSE_BADARGS, undef, $@);
}
if (!defined($expiration)) {
GeniResponse->Create(GENIRESPONSE_BADARGS, undef,
"Could not parse expiration");
}
my $slice = GeniSlice->Lookup($slice_urn);
return GeniResponse->Create(GENIRESPONSE_SEARCHFAILED)
if (!defined($slice));
if (Reservation->ExtendSlice($slice, $expiration, \$reserror, 1)) {
Reservation->FlushAll();
return GeniResponse->Create(GENIRESPONSE_REFUSED, undef, $reserror);
}
Reservation->FlushAll();
return GeniResponse->Create(GENIRESPONSE_SUCCESS);
}
# _Always_ make sure that this 1 is at the end of the file...
1;
......@@ -243,6 +243,7 @@ ProtoGeniDefs::AddModule("cluster",
"SliceUtilizationData" => \&GeniCluster::SliceUtilizationData,
"SliceIdleData" => \&GeniCluster::SliceIdleData,
"SliceOpenstackData" => \&GeniCluster::SliceOpenstackData,
"SliceCheckReservation"=> \&GeniCluster::SliceCheckReservation,
}},
});
......
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