Commit 79d99fa8 authored by Leigh B Stoller's avatar Leigh B Stoller

Fixes/Changes for reservations:

1. Fix the user extend modal to show the proper number of days they can
   extend.

2. Fix the admin extend modal warning when the extension would violate
   max extension, it was not showing. Add new alerts when we cannot get
   max extension from the cluster or no extension at all allowed.

3. Reduce number of days in the box to max allowed. Warn loudly if you
   type a different number and its greater then max extension.

4. Add "force" box to override. Use with caution. Added the plumbing
   through to the back end as new force option to RenewSliver().

5. Add check in RenewSliver() to ask the reservation system if extension
   allowed before doing it. This was missing, should solve some of the
   over book problems.
parent af6daaff
......@@ -2113,9 +2113,9 @@ sub Terminate($)
#
# Ask to extend.
#
sub Extend($$$)
sub Extend($$$$)
{
my ($self, $new_expires, $this_user) = @_;
my ($self, $new_expires, $this_user, $force) = @_;
my $credentials;
my $method;
my @params;
......@@ -2209,10 +2209,14 @@ sub Extend($$$)
unlink($credname);
chomp($extcred);
@params = ({"slice_urn" => $slice->urn(),
my $args = {"slice_urn" => $slice->urn(),
"expiration" => $new_expires,
"credentials" => [@$credentials, $extcred],
});
};
if ($force) {
$args->{"force"} = 1;
}
@params = ($args);
$method = "RenewSlice";
}
my $cmurl = $authority->url();
......
......@@ -1364,7 +1364,7 @@ sub DoTerminate()
#
sub DoExtend()
{
my $force = 0;
my $force = 0;
my $lockdown = 0;
my $errcode = 1;
my $autoextend_maximum = GetSiteVar("aptui/autoextend_maximum");
......@@ -1391,7 +1391,7 @@ sub DoExtend()
usage()
if (!@ARGV);
my $optlist = "m:f:h";
my $optlist = "m:f:hF";
my %options = ();
if (! getopts($optlist, \%options)) {
usage();
......@@ -1399,7 +1399,12 @@ sub DoExtend()
usage()
if (!@ARGV);
my $wanted = shift(@ARGV);
if (defined($options{"F"})) {
# Be careful
$force = 1
if (defined($this_user) && $this_user->IsAdmin());
}
if (defined($options{"m"})) {
$reason = $options{"m"};
}
......@@ -1639,7 +1644,7 @@ sub DoExtend()
my $seconds = $granted * 3600;
$seconds *= 24 if (!$inhours);
if ($errcode = ExtendInternal($slice, $seconds, 0, 0, \$errmsg)) {
if ($errcode = ExtendInternal($slice, $seconds, $force, 0, \$errmsg)) {
goto bad;
}
}
......@@ -1821,7 +1826,7 @@ sub ExtendInternal($$$$$)
my $domain = $sliver->domain();
my $errmsg;
my $response = $sliver->Extend($new_expires, $this_user);
my $response = $sliver->Extend($new_expires, $this_user, $force);
if (!defined($response)) {
$errmsg = "Internal error calling Renew at $domain";
goto bad;
......@@ -2050,8 +2055,7 @@ sub DoMaxExtension()
goto bad;
}
if ($response->code() != GENIRESPONSE_SUCCESS) {
$errmsg = "Failed to get max extension at $domain: ".
$response->output();
$errmsg = $response->output();
# This is something the user should see.
if ($response->code() == GENIRESPONSE_REFUSED ||
......@@ -2292,7 +2296,7 @@ sub DoExtendOld()
my $domain = $sliver->domain();
my $errmsg;
my $response = $sliver->Extend($new_expires, $this_user);
my $response = $sliver->Extend($new_expires, $this_user, $force);
if (!defined($response)) {
$errmsg = "Internal error calling Renew at $domain";
goto bad;
......
......@@ -655,7 +655,7 @@ sub GetTicketAuxAux($$$$$$$$$$$)
}
# Note "checkonly" flag; we do not actually change the slice
# until the ticket is redeemed.
my $tmp = SetSliceExpiration($slice, $expires, 1, 0, @{ $credentials });
my $tmp = SetSliceExpiration($slice, $expires, 1, 0, 0, @{ $credentials });
if (GeniResponse::IsResponse($tmp)) {
return $tmp;
}
......@@ -4007,7 +4007,7 @@ sub SliverWorkAux($$$$$$$$)
$message = "Illegal valid_until in rspec";
goto bad;
}
my $tmp = SetSliceExpiration($slice, $expires, 0, 0, $credential);
my $tmp = SetSliceExpiration($slice, $expires, 0, 0, 0, $credential);
if (GeniResponse::IsResponse($tmp)) {
$message = GeniResponse::output($tmp);
goto bad;
......@@ -5217,12 +5217,12 @@ sub RenewSlice($)
return $credential
if (GeniResponse::IsResponse($credential));
return RenewSliverAux([$credential], $expires, 0);
return RenewSliverAux([$credential], $expires, 0, 0);
}
sub RenewSliverAux($$$)
sub RenewSliverAux($$$$)
{
my ($credentials, $expires, $alap) = @_;
my ($credentials, $expires, $alap, $force) = @_;
my $credential = $credentials->[0];
my $message = "Error renewing aggregate";
my $when;
......@@ -5295,7 +5295,7 @@ sub RenewSliverAux($$$)
}
my $response = SetSliceExpiration($slice,
$expires, 0, $alap, @{ $credentials });
$expires, 0, $alap, $force, @{ $credentials });
if (GeniResponse::IsError($response)) {
$slice->UnLock();
return $response;
......@@ -7700,16 +7700,28 @@ sub KillMonitor($)
#
# alap => extend as long as possible
#
sub SetSliceExpiration($$$$@)
sub SetSliceExpiration($$$$$@)
{
my ($slice, $expiration, $checkonly, $alap, @credentials) = @_;
my ($slice, $expiration, $checkonly, $alap, $force, @credentials) = @_;
my $message = "Error renewing sliver";
my $when;
require Reservation;
#
# Ick, assume first credential is the slice credential. Bad.
#
my $slice_credential = shift(@credentials);
#
# Make sure that a proper credential accompanies the force option.
#
if ($force) {
if (!$slice_credential->HasActualPrivilege("admin")) {
$message = "SetSliceExpiration: Refused force mode ".
"cause credential was too weak";
goto bad;
}
}
#
# Maximum expiration is what the credential says, but we might
......@@ -7834,10 +7846,41 @@ sub SetSliceExpiration($$$$@)
goto bad;
}
}
#
# Now that we have the number we want, make sure the reservation system
# will allow it.
#
if (!$force &&
Reservation->ExtendSlice($slice, $when, \$message, 1, 0)) {
print STDERR "SetSliceExpiration: ExtendSlice(checkonly): $message\n";
$message = "Extension refused by reservation system: $message";
goto bad;
}
if (!$checkonly) {
if ($slice->SetExpiration($when) != 0) {
$message = "could not set expiration time";
goto bad;
if (Reservation->ExtendSlice($slice, $when, \$message, 0, 0)) {
if ($force) {
#
# Do it again, we want to send mail only when we violate.
#
if (Reservation->ExtendSlice($slice, $when, \$message, 0, $force)) {
print STDERR "SetSliceExpiration: ExtendSlice(force): $message\n";
$message = "Forcible extension refused by reservation ".
"system: $message";
goto bad;
}
SENDMAIL($TBOPS, "Slice extension forced by administrator!",
"$slice was forcibly extended!\n".
"The new expiration is " . TBDateStringLocal($when) . "\n\n".
"This may have put the reservation system into overbook.\n",
$TBOPS);
print STDERR "Slice extension forced by administrator!\n";
}
else {
print STDERR "SetSliceExpiration: ExtendSlice(real): $message\n";
$message = "Extension refused by reservation system: $message";
goto bad;
}
}
#
# Mark the expires slot in the experiment, for admission control
......
......@@ -1402,8 +1402,11 @@ sub RenewSlice($)
my $valid_until = $argref->{'valid_until'} || $argref->{'expiration'};
my $credentials = $argref->{'credentials'};
my $alap = 0;
my $force = 0;
# extend as long as possible.
$alap = $argref->{'alap'} if (exists($argref->{'alap'}));
# reservation system override
$force = $argref->{'force'} if (exists($argref->{'force'}));
if (! (defined($credentials) && defined($slice_urn))) {
return GeniResponse->MalformedArgsResponse("Missing arguments");
......@@ -1433,7 +1436,7 @@ sub RenewSlice($)
"Credential does not match the URN");
}
return GeniCM::RenewSliverAux([$credential, @morecreds],
$valid_until, $alap);
$valid_until, $alap, $force);
}
#
......
......@@ -16,6 +16,7 @@ $(function ()
var firstrowTemplate = null;
var secondrowTemplate = null;
var extensionsTemplate = null;
var maxextension = null;
var GENIRESPONSE_REFUSED = 7;
function initialize()
......@@ -122,6 +123,11 @@ $(function ()
"MoreInfo" :
(action == "terminate" ?
"SchedTerminate" : "DenyExtension")));
// Only an extend option for now.
var force = 0;
if (action == "extend" && $('#force-extension-checkbox').is(":checked")) {
force = 1;
}
var callback = function(json) {
sup.HideModal("#waitwait-modal");
......@@ -149,7 +155,8 @@ $(function ()
var xmlthing = sup.CallServerMethod(null, "status", method,
{"uuid" : window.UUID,
"howlong": howlong,
"reason" : reason});
"reason" : reason,
"force" : force});
xmlthing.done(callback);
}
......@@ -169,8 +176,8 @@ $(function ()
$('.format-date').each(function() {
var date = $.trim($(this).html());
if (date != "") {
$(this).html(moment($(this).html())
.format("MMM D h:mm A"));
$(this).html(moment(date)
.format("MMM D, YYYY h:mm A"));
}
});
// lockout change event handler.
......@@ -203,7 +210,7 @@ $(function ()
.attr("disabled", "disabled");
}
// Update the Max Extension
DoMaxExtension();
DoMaxExtension(json.value.expires);
SetupAdminNotes();
}
});
......@@ -381,27 +388,101 @@ $(function ()
//
// Get Max Extension and update the table.
//
function DoMaxExtension()
function DoMaxExtension(expires)
{
// Warn if changing days violates max extension.
var callback = function(json) {
$("#days").on("keyup", function (event) {
if (!maxextension) {
$('#max-extension-nomax').removeClass("hidden");
return;
}
$('#max-extension-nomax').addClass("hidden");
var days = $.trim($("#days").val());
if (days != "") {
days = parseInt(days) || 0;
if (days) {
var when = moment(expires).add(days, "days");
//console.info("when", when.format('lll'));
//console.info("max", maxextension.format('lll'));
if (when.isAfter(maxextension)) {
$('#max-extension-warning .max-extension-date')
.html(when.format('lll'));
$('#max-extension-warning').removeClass("hidden");
}
else {
$('#max-extension-warning').addClass("hidden");
$('#max-extension-warning .max-extension-date').html("");
}
return;
}
}
$('#max-extension-warning').addClass("hidden");
$('#max-extension-warning .max-extension-date').html("");
});
if (json.code) {
console.info("Failed to get max extension: " + json.value);
console.info("Failed to get max extension", json);
$('#days').val("0");
$('#max-extension-nomax').removeClass("hidden");
/*
* Special case, the cluster is saying no extension is possible,
* so it does not even provide a date.
*/
if (json.code == GENIRESPONSE_REFUSED) {
$('#max-extension').html("<span class='text-danger'>" +
"No Extension Possible!</span>");
if (window.DAYS) {
alert("The cluster says no extension is possible at all! " +
"Granting any extension can potentially throw the " +
"reservation system into overbook.");
}
}
else {
$('#max-extension').html("<span class='text-danger'>" +
"Cannot Get Max Extension!</span>");
alert("Unable to get the maximum allowed extension from " +
"the cluster. " +
"Granting any extension can potentially throw the " +
"reservation system into overbook.");
}
return;
}
// Save for checking the extension input field.
maxextension = moment(json.value);
$('#max-extension').html(moment(json.value)
.format("MMM D, YYYY h:mm A"));
/*
* Look to see if the number of days requested is going to be
* greater then the max slice extension. If it is, then we want
* to make sure that is noticed.
*/
var now = new Date();
var max = new Date(json.value);
now.setDate(now.getDate() + window.DAYS);
if (now.getTime() > max.getTime()) {
alert("Granting this full extension would violate the " +
"current maximum allowed extension.");
if (window.DAYS) {
var exp = new Date(expires);
var max = new Date(json.value);
exp.setDate(exp.getDate() + window.DAYS);
if (exp.getTime() > max.getTime()) {
var m1 = moment(exp.getTime());
var m2 = moment(max.getTime());
var diff = m1.diff(m2, "days");
alert("Granting this full extension would violate the " +
"current maximum allowed extension by " + diff + " days. " +
"Granting the extension can potentially throw the " +
"reservation system into overbook.");
// Change the box number to reflect a legal extension.
if (window.DAYS >= diff) {
$('#days').val(window.DAYS - diff);
}
else {
$('#days').val("0");
}
}
}
}
var xmlthing = sup.CallServerMethod(null, "status", "MaxExtension",
......
......@@ -212,7 +212,7 @@ window.ShowExtendModal = (function()
else {
setvalue = 100;
}
console.info("setvalue", day, setvalue);
//console.info("setvalue", day, setvalue);
return setvalue;
}
......@@ -291,7 +291,7 @@ window.ShowExtendModal = (function()
return;
}
}
console.info(howlong);
//console.info(howlong);
$('#extend_value').html(extend_value);
$('#label' + lastlabel + "_request").addClass("hidden");
......@@ -519,7 +519,7 @@ window.ShowExtendModal = (function()
/*
* See if the difference is less then a day.
*/
var now = new Date();
var now = new Date(window.APT_OPTIONS.sliceExpires);
var hours = Math.floor((later.getTime() -
now.getTime()) / (1000 * 3600.0));
......@@ -533,8 +533,9 @@ window.ShowExtendModal = (function()
RequestMaxExtension(hours);
}
else {
maxextend = DateToDays(later);
console.info("Max extension days: ", maxextend);
// Maximum number of days beyond current expiration!
maxextend = Math.floor(hours / 24);
console.info("Max extension days: ", maxextend, hours);
// Show the modal, it is initialized above.
$(modalname).modal('show');
}
......
......@@ -329,6 +329,7 @@ function Do_RequestExtension()
global $instance, $creator, $this_user, $suexec_output;
global $ajax_args;
$inhours = 0;
$force = 0;
$autoextend_maximum = TBGetSiteVar("aptui/autoextend_maximum");
if (StatusSetupAjax(1)) {
......@@ -374,6 +375,9 @@ function Do_RequestExtension()
if (isset($ajax_args["reason"]) && $ajax_args["reason"] != "") {
$reason = $ajax_args["reason"];
}
if (isset($ajax_args["force"]) && $ajax_args["force"]) {
$force = 1;
}
}
elseif (isset($ajax_args["inhours"])) {
#
......@@ -407,7 +411,8 @@ function Do_RequestExtension()
"webmanage_instance -t " . $webtask->task_id() . " -- ".
" extend $uuid " .
(isset($filename) ? "-f $filename " : "").
($inhours ? "-h " : "") . "$wanted",
($inhours ? "-h " : "") .
($force ? "-F " : "") . "$wanted",
SUEXEC_ACTION_IGNORE);
$webtask->Refresh();
if (isset($filename)) {
......@@ -1934,6 +1939,12 @@ function Do_MaxExtension()
{
global $instance, $creator, $TBADMINGROUP, $suexec_output;
if (0) {
$blob = "2017-11-06T18:09:59Z";
SPITAJAX_RESPONSE($blob);
return;
}
if (StatusSetupAjax(0)) {
return;
}
......
......@@ -79,11 +79,26 @@ pre {
style='margin-left: 20px;'
id='do-extension'
type='submit' name='request'>Extend</button>
<span data-toggle='popover'
data-delay='{"hide":500, "show":500}'
data-content="When checked, the portal will force the cluster to grant
the extension even if it causes a reservation system
overbooking situation. Be careful!">
Force: <input type="checkbox" id="force-extension-checkbox"></span>
<button class='btn btn-primary btn-sm'
style='margin-left: 30px;'
id='do-moreinfo'
type='submit' name='moreinfo'>More Info</button>
</div>
<div id="max-extension-warning" class="hidden">
<span class="text-danger">Granting an extension to
<span class="max-extension-date"></span>
may cause a reservation overbook situation!</span>
</div>
<div id="max-extension-nomax" class="hidden">
<span class="text-danger">Granting any extension
may cause a reservation overbook situation!</span>
</div>
</center>
</div>
</div>
......
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