Commit f9cb198e authored by Leigh Stoller's avatar Leigh Stoller

Checkpoint changes to usage display and extend modal.

parent 71d89c86
......@@ -184,7 +184,6 @@ echo json_encode($instances);
echo "</script>\n";
echo "<link rel='stylesheet' href='css/tablesorter.css'>\n";
echo "<link rel='stylesheet' href='css/jQRangeSlider.css'>\n";
echo "<script src='js/lib/jquery.min.js'></script>\n";
echo "<script src='js/lib/jquery-ui.js'></script>\n";
echo "<script src='js/lib/jQRangeSlider/jQRangeSliderMouseTouch.js'></script>\n";
echo "<script src='js/lib/jQRangeSlider/jQRangeSliderDraggable.js'></script>\n";
......
......@@ -104,6 +104,8 @@ class Instance
function extension_reason() { return $this->field('extension_reason'); }
function extension_history() { return $this->field('extension_history'); }
function extension_lockout() { return $this->field('extension_adminonly'); }
function physnode_count() { return $this->field('physnode_count'); }
function virtnode_count() { return $this->field('virtnode_count'); }
function servername() { return $this->field('servername'); }
function aggregate_urn(){ return $this->field('aggregate_urn'); }
function IsAPT() {
......@@ -409,20 +411,129 @@ class Instance
$phours = 0;
$query_result =
DBQueryFatal("select physnode_count, ".
" truncate(physnode_count * ".
DBQueryFatal("select sum(physnode_count), ".
" truncate(sum(physnode_count * ".
" ((UNIX_TIMESTAMP(now()) - ".
" UNIX_TIMESTAMP(created)) / 3600.0),2) as phours ".
" UNIX_TIMESTAMP(created)) / 3600.0)),2) as phours ".
" from apt_instances ".
"where creator_idx='$user_idx' and physnode_count>0");
while ($row = mysql_fetch_array($query_result)) {
$pcount += $row["physnode_count"];
$phours += $row["phours"];
}
$row = mysql_fetch_array($query_result);
$pcount = $row[0] ? $row[0] : 0;
$phours = $row[1] ? $row[1] : 0;
return array($pcount, $phours);
}
#
# Usage over the last week. Just phours, cause pcount is not very useful.
#
function WeeksUsage($user) {
$user_idx = $user->idx();
$weekago = time() - (3600 * 24 * 7);
$phours = 0;
#
# This gets existing experiments back one week.
#
$query_result =
DBQueryFatal("select physnode_count,UNIX_TIMESTAMP(created) ".
" from apt_instances ".
"where creator_idx='$user_idx' and ".
" physnode_count>0");
while ($row = mysql_fetch_array($query_result)) {
$pnodes = $row[0];
$created = $row[1];
if ($created < $weekago)
$diff = (3600 * 24 * 7);
else
$diff = time() - $created;
$phours += $pnodes * ($diff / 3600.0);
}
#
# This gets experiments terminated in the last week.
#
$query_result =
DBQueryFatal("select physnode_count,UNIX_TIMESTAMP(created), ".
" UNIX_TIMESTAMP(destroyed) ".
" from apt_instance_history ".
"where creator_idx='$user_idx' and ".
" physnode_count>0 and " .
" destroyed>DATE_SUB(curdate(), INTERVAL 1 WEEK)");
while ($row = mysql_fetch_array($query_result)) {
$pnodes = $row[0];
$created = $row[1];
$destroyed = $row[2];
if ($created < $weekago)
$diff = $destroyed - $weekago;
else
$diff = $destroyed - $created;
$phours += $pnodes * ($diff / 3600.0);
}
return $phours;
}
#
# Usage over the last months Just phours, cause pcount is not very useful.
#
function MonthsUsage($user) {
$user_idx = $user->idx();
$monthago = time() - (3600 * 24 * 28);
$phours = 0;
#
# This gets existing experiments back one week.
#
$query_result =
DBQueryFatal("select physnode_count,UNIX_TIMESTAMP(created) ".
" from apt_instances ".
"where creator_idx='$user_idx' and ".
" physnode_count>0");
while ($row = mysql_fetch_array($query_result)) {
$pnodes = $row[0];
$created = $row[1];
if ($created < $monthago)
$diff = (3600 * 24 * 28);
else
$diff = time() - $created;
$phours += $pnodes * ($diff / 3600.0);
}
#
# This gets experiments terminated in the last week.
#
$query_result =
DBQueryFatal("select physnode_count,UNIX_TIMESTAMP(created), ".
" UNIX_TIMESTAMP(destroyed) ".
" from apt_instance_history ".
"where creator_idx='$user_idx' and ".
" physnode_count>0 and " .
" destroyed>DATE_SUB(curdate(), INTERVAL 1 MONTH)");
while ($row = mysql_fetch_array($query_result)) {
$pnodes = $row[0];
$created = $row[1];
$destroyed = $row[2];
if ($created < $monthago)
$diff = $destroyed - $monthago;
else
$diff = $destroyed - $created;
$phours += $pnodes * ($diff / 3600.0);
}
return $phours;
}
#
# Return Caching Token, either the latest commit hash
# or the current time for development trees.
......
......@@ -17,6 +17,8 @@ define(['underscore', 'js/quickvm_sup',
var uuid = 0;
var callback = null;
var howlong = 1; // Number of days being requested.
var physnode_count = 0;
var physnode_hours = 0;
function Initialize()
{
......@@ -51,6 +53,8 @@ define(['underscore', 'js/quickvm_sup',
$("#datepicker").focus();
return false;
}
var howlong = DateToDays();
$('#future_usage').text(physnode_count * howlong * 24);
});
}
......@@ -62,6 +66,12 @@ define(['underscore', 'js/quickvm_sup',
});
// Clear existing text.
$('#why_extend').val('');
// Current usage.
if (physnode_count) {
$("#extend_usage").removeClass("hidden");
$('#current_usage').text(physnode_hours);
$('#future_usage').text(physnode_count * 24);
}
}
function InitializeSlider()
......@@ -123,6 +133,30 @@ define(['underscore', 'js/quickvm_sup',
}
}
/*
* Pick which instructions to show (label number) based on number
* of phys/virt nodes. Hacky.
*/
function PickInstructions(days) {
// No physical nodes, we require minimal info and will always
// grant the extension.
if (physnode_count == 0) return 0;
// Long term extension request, must justify.
if (days > (12 * 7)) return 3;
// Under 10 days of node hours used and asking for a short
// extension, minimal info is okay.
if (physnode_hours < (10 * 24) && (physnode_count * days) <= 10) {
return 0;
}
if (days <= 7) {
return 0;
}
if (days < (12 * 7)) {
return 1;
}
return 2;
}
/*
* User has changed the slider. Show new instructions.
*/
......@@ -147,29 +181,29 @@ define(['underscore', 'js/quickvm_sup',
var day = Math.round(which / divider) + 1;
extend_value = day + " days";
setvalue = Math.round((day - 1) * divider);
label = 0;
howlong = day;
label = PickInstructions(howlong);
}
else if (which <= 66) {
var divider = 33 / 20.0;
var day = Math.round((which - 33) / divider) + 7;
extend_value = day + " days";
setvalue = Math.round((day - 7) * divider) + 33;
label = 1;
howlong = day;
label = PickInstructions(howlong);
}
else if (which <= 97) {
var divider = 33 / 8.0;
var week = Math.round((which - 66) / divider) + 4;
extend_value = week + " weeks";
setvalue = Math.round((week - 4) * divider) + 66;
label = 2;
howlong = week * 7;
label = PickInstructions(howlong);
}
else {
extend_value = "Longer";
setvalue = 100;
label = 3;
label = 2;
// User has to fill in the date box, then we can figure
// it out.
howlong = null;
......@@ -179,6 +213,10 @@ define(['underscore', 'js/quickvm_sup',
$('#label' + lastlabel + "_request").addClass("hidden");
$('#label' + label + "_request").removeClass("hidden");
if (howlong) {
$('#future_usage').text(physnode_count * howlong * 24);
}
// For the char countdown below.
minchars = $('#label' + label + "_request").attr('data-minchars');
UpdateCountdown();
......@@ -213,6 +251,25 @@ define(['underscore', 'js/quickvm_sup',
$('#extend_counter_msg').html(msg);
}
/*
* Convert date to howlong in days.
*/
function DateToDays()
{
var days = 0;
var today = new Date();
var later = new Date($('#datepicker').val());
var diff = (later - today);
if (diff < 0) {
alert("No time travel to the past please");
$("#datepicker").focus();
return 0;
}
days = parseInt((diff / 1000) / (3600 * 24));
return (days < 1 ? 1 : days);
}
//
// Request experiment extension.
//
......@@ -233,20 +290,7 @@ define(['underscore', 'js/quickvm_sup',
$("#datepicker").focus();
return;
}
/*
* Convert date to howlong in days.
*/
var today = new Date();
var later = new Date($('#datepicker').val());
var diff = (later - today);
if (diff < 0) {
alert("No time travel to the past please");
$("#datepicker").focus();
return;
}
howlong = parseInt((diff / 1000) / (3600 * 24));
if (howlong < 1)
howlong = 1;
howlong = DateToDays();
}
reason = $("#why_extend").val();
if (reason.trim().length == 0) {
......@@ -296,12 +340,15 @@ define(['underscore', 'js/quickvm_sup',
$(button).attr("disabled", "disabled");
}
}
return function(thisuuid, func, admin, guest, extendfor, url)
return function(thisuuid, func, admin, guest, extendfor,
url, pcount, phours)
{
isadmin = admin;
// isadmin = admin;
isguest = guest;
uuid = thisuuid;
callback = func;
physnode_count = pcount;
physnode_hours = phours;
$('#extend_div').html(isadmin ?
adminExtendString : isguest ?
......
......@@ -181,7 +181,6 @@ function SPITFORM($formfields, $errors)
echo " window.SNAPUUID = '$snapuuid';\n";
}
echo "</script>\n";
echo "<script src='js/lib/jquery.min.js'></script>\n";
echo "<script src='js/lib/jquery-ui.js'></script>\n";
echo "<script src='js/lib/jquery.appendGrid-1.3.1.min.js'></script>\n";
echo "<script src='js/lib/codemirror-min.js'></script>\n";
......
......@@ -80,6 +80,7 @@ if ($TBMAINSITE && $_SERVER["SERVER_NAME"] == "www.aptlab.net") {
$GOOGLEUA = 'UA-42844769-3';
$TBMAILTAG = "aptlab.net";
$EXTENSIONS = "portal-extensions@aptlab.net";
$TBAUTHTIMEOUT= (24 * 3600 * 7);
# For devel trees
if (preg_match("/\/([\w\/]+)$/", $WWW, $matches)) {
$APTBASE .= "/" . $matches[1];
......@@ -102,6 +103,7 @@ elseif (0 || ($TBMAINSITE && $_SERVER["SERVER_NAME"] == "www.cloudlab.us")) {
$GOOGLEUA = 'UA-42844769-2';
$TBMAILTAG = "cloudlab.us";
$EXTENSIONS = "portal-extensions@cloudlab.us";
$TBAUTHTIMEOUT= (24 * 3600 * 14);
# For devel trees
if (preg_match("/\/([\w\/]+)$/", $WWW, $matches)) {
$APTBASE .= "/" . $matches[1];
......@@ -165,6 +167,7 @@ $PAGEHEADER_FUNCTION = function($thinheader = 0, $ignore1 = NULL,
<link rel='stylesheet' href='css/bootstrap.css'>
<link rel='stylesheet' href='css/quickvm.css'>
<link rel='stylesheet' href='css/$APTSTYLE'>";
echo "<script src='js/lib/jquery.min.js'></script>\n";
echo "<script>APT_CACHE_TOKEN='" . Instance::CacheToken() . "';</script>";
echo "<script src='js/common.js?nocache=asdfasdf'></script>
<link rel='stylesheet' href='css/jquery-steps.css'>
......@@ -323,15 +326,34 @@ $PAGEHEADER_FUNCTION = function($thinheader = 0, $ignore1 = NULL,
}
if ($login_user) {
list($pcount, $phours) = Instance::CurrentUsage($login_user);
if ($pcount) {
$average = sprintf("%.2f", $phours / $pcount);
echo "<center style='margin-bottom: 5px; margin-top: -8px'>
<span class=text-warning>
You are using $pcount physical nodes
(average $average hours per node)
</span></center>\n";
$weeksusage = Instance::WeeksUsage($login_user);
$monthsusage = Instance::MonthsUsage($login_user);
if ($phours || $weeksusage || $monthsusage) {
echo "<center style='margin-bottom: 5px; margin-top: -8px'>";
if ($phours) {
$phours = sprintf("%.2f", $phours);
echo "<span class='text-info'>
Current Usage: $phours Node Hours</span>";
}
if ($weeksusage) {
$weeksusage = sprintf("%.0f", $weeksusage);
if ($phours) echo ", ";
echo "<span class='text-warning'>
Prev Week: $weeksusage</span>";
}
if ($monthsusage) {
$monthsusage = sprintf("%.0f", $monthsusage);
if ($phours || $weeksusage) echo ", ";
echo "<span class='text-danger'>
Prev Month: $monthsusage</span>";
}
echo "<a href='#' class='btn btn-xs' data-toggle='modal' ".
"data-target='#myusage_modal'> ".
"<span class='glyphicon glyphicon-question-sign'></span> ".
"</a>\n";
echo "</center>\n";
}
readfile("template/myusage.html");
}
if (!NOLOGINS() && !$login_user && $page_title != "Login") {
......@@ -424,7 +446,6 @@ function SPITREQUIRE($main, $extras = "")
{
global $spatrequired;
echo "<script src='js/lib/jquery.min.js'></script>\n";
echo $extras;
echo "<script src='js/lib/bootstrap.js'></script>\n";
echo "<script src='js/lib/require.js' data-main='js/$main'></script>\n";
......
......@@ -220,6 +220,13 @@ echo " window.APT_OPTIONS.publicURL = $public_url;\n";
echo " window.APT_OPTIONS.lockdown = $lockdown;\n";
echo " window.APT_OPTIONS.lockout = $lockout;\n";
echo " window.APT_OPTIONS.AJAXURL = 'server-ajax.php';\n";
echo " window.APT_OPTIONS.physnode_count = " .
$instance->physnode_count() . ";\n";
echo " window.APT_OPTIONS.virtnode_count = " .
$instance->virtnode_count() . ";\n";
echo " window.APT_OPTIONS.physnode_hours = " .
sprintf("%.2f;\n", $instance->physnode_count() *
((time() - strtotime($slice->created())) / 3600));
echo " window.APT_OPTIONS.freenodesurl = '$freenodes_url';\n";
if (isset($extend) && $extend != "") {
echo " window.APT_OPTIONS.extend = $extend;\n";
......
......@@ -431,7 +431,6 @@ else {
echo " window.MAX = null;\n";
}
echo "</script>\n";
echo "<script src='js/lib/jquery.min.js'></script>\n";
echo "<script src='js/lib/jquery-ui.js'></script>\n";
echo "<script src='js/lib/jQRangeSlider/jQRangeSliderMouseTouch.js'></script>\n";
echo "<script src='js/lib/jQRangeSlider/jQRangeSliderDraggable.js'></script>\n";
......
<div id='myusage_modal' class='modal' style='z-index:1051;'>
<div class='modal-dialog'>
<div class='modal-content'>
<div class='modal-body'>
<button type='button'
class='btn btn-default btn-sm pull-right'
data-dismiss='modal' aria-hidden='true'>&times;</button>
<p>
We tell you your node usage in terms of <em>node hours</em>; the
number of nodes you are using multiplied by the number of hours
you have been using those nodes. We feel this is the best way to
tell you how much of the testbed your are using.
</p>
<p>
<b>Large numbers are warning signs</b>; many experiments (not all
of course) can be performed in less then a week or month. It also
informs our decisions when you request an extension; users who
are performing small experiments or short experiments will
typically be granted extensions without much fuss. Users who have
been consuming large amounts of resources will be required to
justify their usage to us, and in extreme cases (say, if the
testbed is in high demand) might not be granted extensions.
</p>
<p>
You can always find your current usage by clicking on <b>My
Experiments</b> in the <b>Actions</b> menu. You can view
your historical usage by clicking on <b>My History</b>.
</p>
</div>
</div>
</div>
</div>
<!-- This is the extend modal -->
<style>
#extend_usage {
text-align: center;
display: table;
}
#extend_usage a {
position: relative;
vertical-align: middle;
display: table-cell;
}
#extend_usage div {
vertical-align: middle;
display: table-cell;
}
</style>
<div id='extend_modal' class='modal fade'>
<div class='modal-dialog'>
<div class='modal-content'>
......@@ -14,45 +30,55 @@
<span id='extend_value'>1 day</span></h4>
</center>
<div id='extend_slider'></div>
<br>
<div class='row'>
<div class='col-lg-10 col-lg-offset-1
col-md-10 col-md-offset-1
col-sm-12 col-sm-offset-0
col-xs-12 col-xs-offset-0'>
<div id='extend_usage' class='hidden center-block'>
<a href='#' class='btn btn-xs' data-toggle='modal'
data-target='#myusage_modal'>
<span class='glyphicon glyphicon-question-sign'></span>
</a>
<div>
<span>Current Usage:</span>
<span id='current_usage' class='text-info'></span>
<span class='text-info'>Node Hours</span>
<br>
<span>Requesting:</span>
<span id='future_usage' class='text-info'></span>
<span class='text-info'>more Node Hours</span>
</div>
</div><br>
<div id='label0_request' data-minchars='120'>
<p>
Please provide a short explanation (a few sentences)
telling us why need more time. Then click on the
explaining why you need more time. Then click on the
request button.
</p>
</div>
<div id='label1_request' class='hidden' data-minchars='240'>
<p>
Please provide a short explanation (a few sentences)
telling us why need more time. Then click on the
request button. You will receive email when your
extension is granted, if you do not hear back in a
day or two, please contact us.
</p>
</div>
<div id='label2_request' class='hidden' data-minchars='380'>
<p>
Extensions this large require a more detailed
explanation. Please provide a paragraph, and then
click on the request button. You will receive email
when your extension is granted, if you do not hear
back in a day or two, please contact us.
explaining why you need more time. Then click on the
request button. The more <em>node hours</em> you
want, the more rationale we want to see. Small
experiments and/or small extension requests, are
typically approved very quickly, but if you want a
lot more node hours, then be sure to tell us a good
story.
</p>
</div>
<div id='label3_request' class='hidden' data-minchars='512'>
<div id='label2_request' class='hidden' data-minchars='512'>
<p>
Please select a date and be sure to tell us in
detail why you need such a long extension. Be sure
include a phone number where we can contact you to
Please select a date and be sure to tell us in detail
why you need such a long extension; such long
extensions are rare and require approval from
the <em>resource management committee</em>. Be sure
to include a phone number where we can contact you to
discuss your extension. Then click on the request
button. You will receive email when your extension is
granted, if you do not hear back in a day or two,
granted, but if you do not hear back in a day or two,
please contact us.
</p>
<center><input type='text' id='datepicker'
......
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