Commit eda2ea39 authored by Leigh B Stoller's avatar Leigh B Stoller
Browse files

Give me stats or give me death.

parent 9be2e098
...@@ -38,7 +38,7 @@ sub usage() ...@@ -38,7 +38,7 @@ sub usage()
print("Usage: manage_instance snapshot instance ". print("Usage: manage_instance snapshot instance ".
"[-n node_id] [-i imagename] [-u node|all]\n"); "[-n node_id] [-i imagename] [-u node|all]\n");
print("Usage: manage_instance consoleurl instance node\n"); print("Usage: manage_instance consoleurl instance node\n");
print("Usage: manage_instance extend instance seconds\n"); print("Usage: manage_instance extend instance [-f] seconds\n");
print("Usage: manage_instance terminate instance\n"); print("Usage: manage_instance terminate instance\n");
print("Usage: manage_instance refresh instance\n"); print("Usage: manage_instance refresh instance\n");
print("Usage: manage_instance reboot instance node_id [node_id ...]\n"); print("Usage: manage_instance reboot instance node_id [node_id ...]\n");
...@@ -755,15 +755,26 @@ sub DoTerminate() ...@@ -755,15 +755,26 @@ sub DoTerminate()
# #
sub DoExtend() sub DoExtend()
{ {
my $force = 0;
usage() usage()
if (!@ARGV); if (!@ARGV);
if (@ARGV == 2) {
my $arg = shift(@ARGV);
if ($arg eq "-f") {
$force = 1;
}
else {
usage();
}
}
my $seconds = shift(@ARGV); my $seconds = shift(@ARGV);
if ($seconds !~ /^\d*$/) { if ($seconds !~ /^\d*$/) {
usage(); usage();
} }
if ($instance->status() eq "failed") { if ($instance->status() eq "failed" && !$force) {
fatal("Cannot extend failed instance!"); fatal("Cannot extend failed instance!");
} }
my $slice = $instance->GetGeniSlice(); my $slice = $instance->GetGeniSlice();
......
...@@ -154,6 +154,7 @@ APTUIFILES += $(wildcard $(SRCDIR)/aptui/*.gif) ...@@ -154,6 +154,7 @@ APTUIFILES += $(wildcard $(SRCDIR)/aptui/*.gif)
APTUIFILES += $(wildcard $(SRCDIR)/aptui/.htaccess) APTUIFILES += $(wildcard $(SRCDIR)/aptui/.htaccess)
APTJSFILES = $(wildcard $(SRCDIR)/aptui/js/*.js) APTJSFILES = $(wildcard $(SRCDIR)/aptui/js/*.js)
APTLIBFILES = $(wildcard $(SRCDIR)/aptui/js/lib/*.js) APTLIBFILES = $(wildcard $(SRCDIR)/aptui/js/lib/*.js)
APTJQRFILES = $(wildcard $(SRCDIR)/aptui/js/lib/jQRangeSlider/*.js)
APTTEMPLATES = $(wildcard $(SRCDIR)/aptui/template/*.html) APTTEMPLATES = $(wildcard $(SRCDIR)/aptui/template/*.html)
APTCSSFILES = $(wildcard $(SRCDIR)/aptui/css/*.css) APTCSSFILES = $(wildcard $(SRCDIR)/aptui/css/*.css)
APTFONTS = $(wildcard $(SRCDIR)/aptui/fonts/*) APTFONTS = $(wildcard $(SRCDIR)/aptui/fonts/*)
...@@ -218,6 +219,7 @@ ALLBLOB = $(notdir $(BLOBFILES)) ...@@ -218,6 +219,7 @@ ALLBLOB = $(notdir $(BLOBFILES))
ALLAPTUI = $(notdir $(APTUIFILES)) ALLAPTUI = $(notdir $(APTUIFILES))
ALLAPTJS = $(notdir $(APTJSFILES)) ALLAPTJS = $(notdir $(APTJSFILES))
ALLAPTLIB = $(notdir $(APTLIBFILES)) ALLAPTLIB = $(notdir $(APTLIBFILES))
ALLAPTJQR = $(notdir $(APTJQRFILES))
ALLAPTTEMPLATES = $(notdir $(APTTEMPLATES)) ALLAPTTEMPLATES = $(notdir $(APTTEMPLATES))
ALLAPTCSS = $(notdir $(APTCSSFILES)) ALLAPTCSS = $(notdir $(APTCSSFILES))
ALLAPTFONTS = $(notdir $(APTFONTS)) ALLAPTFONTS = $(notdir $(APTFONTS))
...@@ -266,6 +268,7 @@ endif ...@@ -266,6 +268,7 @@ endif
apt-install: $(addprefix $(INSTALL_WWWDIR)/apt/, $(ALLAPTUI)) \ apt-install: $(addprefix $(INSTALL_WWWDIR)/apt/, $(ALLAPTUI)) \
$(addprefix $(INSTALL_WWWDIR)/apt/js/, $(ALLAPTJS)) \ $(addprefix $(INSTALL_WWWDIR)/apt/js/, $(ALLAPTJS)) \
$(addprefix $(INSTALL_WWWDIR)/apt/js/lib/, $(ALLAPTLIB)) \ $(addprefix $(INSTALL_WWWDIR)/apt/js/lib/, $(ALLAPTLIB)) \
$(addprefix $(INSTALL_WWWDIR)/apt/js/lib/jQRangeSlider/, $(ALLAPTJQR)) \
$(addprefix $(INSTALL_WWWDIR)/apt/template/, $(ALLAPTTEMPLATES)) \ $(addprefix $(INSTALL_WWWDIR)/apt/template/, $(ALLAPTTEMPLATES)) \
$(addprefix $(INSTALL_WWWDIR)/apt/css/, $(ALLAPTCSS)) \ $(addprefix $(INSTALL_WWWDIR)/apt/css/, $(ALLAPTCSS)) \
$(addprefix $(INSTALL_WWWDIR)/apt/fonts/, $(ALLAPTFONTS)) \ $(addprefix $(INSTALL_WWWDIR)/apt/fonts/, $(ALLAPTFONTS)) \
......
<?php <?php
# #
# Copyright (c) 2000-2014 University of Utah and the Flux Group. # Copyright (c) 2000-2015 University of Utah and the Flux Group.
# #
# {{{EMULAB-LICENSE # {{{EMULAB-LICENSE
# #
...@@ -28,6 +28,13 @@ include("quickvm_sup.php"); ...@@ -28,6 +28,13 @@ include("quickvm_sup.php");
include("profile_defs.php"); include("profile_defs.php");
$page_title = "My Profiles"; $page_title = "My Profiles";
#
# Verify page arguments.
#
$optargs = OptionalPageArguments("target_user", PAGEARG_USER,
"target_project", PAGEARG_PROJECT,
"min", PAGEARG_INTEGER,
"max", PAGEARG_INTEGER);
# #
# Get current user. # Get current user.
# #
...@@ -36,64 +43,106 @@ $this_user = CheckLoginOrRedirect(); ...@@ -36,64 +43,106 @@ $this_user = CheckLoginOrRedirect();
SPITHEADER(1); SPITHEADER(1);
if (!ISADMIN()) { if (!ISADMIN()) {
SPITUSERERROR("Not enough permission to view this page!"); if (isset($target_user)) {
if (!$target_user->SameUser($this_user)) {
SPITUSERERROR("Not enough permission to view this page!");
}
}
elseif (isset($target_project)) {
$approved = 0;
if (!$target_project->IsMember($this_user, $approved) && $approved) {
SPITUSERERROR("Not enough permission to view this page!");
}
}
else {
$target_user = $this_user;
}
} }
$instances = array(); $instances = array();
# #
# First existing instances and then the history table. # Allow for targeted searches
# #
$query1_result = $whereclause = "";
DBQueryFatal("select i.uuid,i.profile_version,i.created,'' as destroyed, ".
" i.creator,p.uuid as profile_uuid,p.name,p.pid,u.email ". if (isset($target_user)) {
" from apt_instances as i ". $target_idx = $target_user->idx();
"left join apt_profile_versions as p on ". $whereclause = "where h.creator_idx='$target_idx'";
" p.profileid=i.profile_id and ". }
" p.version=i.profile_version ". elseif (isset($target_project)) {
"left join geni.geni_users as u on u.uuid=i.creator_uuid ". $target_idx = $target_project->pid_idx();
"order by i.created desc"); $whereclause = "where h.pid_idx='$target_idx'";
$query2_result = }
if (isset($min) || isset($max)) {
if ($whereclause != "") {
$whereclause = "$whereclause and ";
}
else {
$whereclause = "where ";
}
if (isset($min)) {
$whereclause .= "UNIX_TIMESTAMP(h.created) > $min ";
if (isset($max)) {
$whereclause .= "and ";
}
}
if (isset($max)) {
$whereclause .= "UNIX_TIMESTAMP(h.created) < $max ";
}
}
$query_result =
DBQueryFatal("select h.uuid,h.profile_version,h.created,h.destroyed, ". DBQueryFatal("select h.uuid,h.profile_version,h.created,h.destroyed, ".
" h.creator,p.uuid as profile_uuid,p.name,p.pid,u.email ". " h.creator,p.uuid as profile_uuid,p.name,p.pid,u.email, ".
" h.physnode_count,h.virtnode_count, ".
" truncate(h.physnode_count * ".
" ((UNIX_TIMESTAMP(h.destroyed) - ".
" UNIX_TIMESTAMP(h.created)) / 3600.0),2) as phours ".
" from apt_instance_history as h ". " from apt_instance_history as h ".
"left join apt_profile_versions as p on ". "left join apt_profile_versions as p on ".
" p.profileid=h.profile_id and ". " p.profileid=h.profile_id and ".
" p.version=h.profile_version ". " p.version=h.profile_version ".
"left join geni.geni_users as u on u.uuid=h.creator_uuid ". "left join geni.geni_users as u on u.uuid=h.creator_uuid ".
$whereclause . " " .
"order by h.created desc"); "order by h.created desc");
if (mysql_num_rows($query1_result) == 0 && if (mysql_num_rows($query_result) == 0) {
mysql_num_rows($query2_result) == 0) {
$message = "<b>Oops, there is no activity to show you.</b><br>"; $message = "<b>Oops, there is no activity to show you.</b><br>";
SPITUSERERROR($message); SPITUSERERROR($message);
exit(); exit();
} }
foreach (array($query1_result, $query2_result) as $query_result) { if (1) {
while ($row = mysql_fetch_array($query_result)) { while ($row = mysql_fetch_array($query_result)) {
$uuid = $row["uuid"];
$pname = $row["name"]; $pname = $row["name"];
$pproj = $row["pid"]; $pproj = $row["pid"];
$puuid = $row["profile_uuid"]; $puuid = $row["profile_uuid"];
$pversion = $row["profile_version"]; $created = DateStringGMT($row["created"]);
$created = $row["created"]; $destroyed = DateStringGMT($row["destroyed"]);
$destroyed = $row["destroyed"];
$creator = $row["creator"]; $creator = $row["creator"];
$email = $row["email"]; $email = $row["email"];
$pcount = $row["physnode_count"];
$vcount = $row["virtnode_count"];
$phours = $row["phours"];
# Backwards compat.
if (!isset($pproj)) {
$pproj = "";
}
if (!isset($destroyed)) {
$destroyed = "";
}
# If a guest user, use email instead. # If a guest user, use email instead.
if (isset($email)) { if (isset($email)) {
$creator = $email; $creator = $email;
} }
$instance = array(); # Save space with array instead of hash.
$instance["uuid"] = $uuid; $instance =
$instance["p_name"] = $pname; array($pname, $pproj, $puuid, $pcount, $vcount,
$instance["p_pid"] = $pproj; $creator, $created, $destroyed, $phours);
$instance["p_uuid"] = $puuid;
$instance["p_version"] = $pversion;
$instance["creator"] = $creator;
$instance["created"] = $created;
$instance["destroyed"] = $destroyed;
$instances[] = $instance; $instances[] = $instance;
} }
} }
...@@ -103,11 +152,47 @@ echo "<div id='activity-body'></div>\n"; ...@@ -103,11 +152,47 @@ echo "<div id='activity-body'></div>\n";
echo "<script type='text/javascript'>\n"; echo "<script type='text/javascript'>\n";
echo " window.AJAXURL = 'server-ajax.php';\n"; echo " window.AJAXURL = 'server-ajax.php';\n";
if (isset($min)) {
echo " window.MIN = $min;\n";
}
else {
echo " window.MIN = null;\n";
}
if (isset($max)) {
echo " window.MAX = $max;\n";
}
else {
echo " window.MAX = null;\n";
}
if (isset($target_user)) {
echo " window.ARG = 'user=$target_idx';\n";
}
elseif (isset($target_project)) {
echo " window.ARG = 'project=$target_idx';\n";
}
else {
echo " window.ARG = null;\n";
}
echo "</script>\n"; echo "</script>\n";
echo "<script type='text/plain' id='instances-json'>\n"; echo "<script type='text/plain' id='instances-json'>\n";
echo json_encode($instances); echo json_encode($instances);
echo "</script>\n"; echo "</script>\n";
echo "<script src='js/lib/jquery-2.0.3.min.js'></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";
echo "<script src='js/lib/jQRangeSlider/jQRangeSliderHandle.js'></script>\n";
echo "<script src='js/lib/jQRangeSlider/jQRangeSliderBar.js'></script>\n";
echo "<script src='js/lib/jQRangeSlider/jQRangeSliderLabel.js'></script>\n";
echo "<script src='js/lib/jQRangeSlider/jQRangeSlider.js'></script>\n";
echo "<script src='js/lib/jQRangeSlider/jQDateRangeSliderHandle.js'></script>\n";
echo "<script src='js/lib/jQRangeSlider/jQDateRangeSlider.js'></script>\n";
echo "<script src='js/lib/jQRangeSlider/jQRuler.js'></script>\n";
echo "<script src='js/lib/jquery.tablesorter.min.js'></script>\n";
echo "<script src='js/lib/jquery.tablesorter.widgets.min.js'></script>\n";
echo "<script src='js/lib/jquery.tablesorter.widget-math.js'></script>\n";
echo "<script src='js/lib/bootstrap.js'></script>\n"; echo "<script src='js/lib/bootstrap.js'></script>\n";
echo "<script src='js/lib/require.js' data-main='js/activity'></script>\n"; echo "<script src='js/lib/require.js' data-main='js/activity'></script>\n";
......
...@@ -332,5 +332,28 @@ class Instance ...@@ -332,5 +332,28 @@ class Instance
} }
return 0; return 0;
} }
#
# Determine user current usage.
#
function CurrentUsage($user) {
$user_idx = $user->idx();
$pcount = 0;
$phours = 0;
$query_result =
DBQueryFatal("select physnode_count, ".
" truncate(physnode_count * ".
" ((UNIX_TIMESTAMP(now()) - ".
" 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"];
}
return array($pcount, $phours);
}
} }
?> ?>
require(window.APT_OPTIONS.configObject, require(window.APT_OPTIONS.configObject,
['underscore', 'js/quickvm_sup', ['underscore', 'js/quickvm_sup', 'moment',
'js/lib/text!template/activity.html'], 'js/lib/text!template/activity.html'],
function (_, sup, profileString) function (_, sup, moment, profileString)
{ {
'use strict'; 'use strict';
var ajaxurl = null; var ajaxurl = null;
...@@ -11,11 +11,86 @@ function (_, sup, profileString) ...@@ -11,11 +11,86 @@ function (_, sup, profileString)
{ {
window.APT_OPTIONS.initialize(sup); window.APT_OPTIONS.initialize(sup);
ajaxurl = window.AJAXURL; ajaxurl = window.AJAXURL;
var default_min = new Date(2014, 6, 1);
var default_max = new Date();
if (window.MIN) {
default_min = new Date(window.MIN * 1000);
}
if (window.MAX) {
default_max = new Date(window.MAX * 1000);
}
var instances = var instances =
JSON.parse(_.unescape($('#instances-json')[0].textContent)); JSON.parse(_.unescape($('#instances-json')[0].textContent));
var activity_html = profileTemplate({instances: instances}); var activity_html = profileTemplate({instances: instances});
$('#activity-body').html(activity_html); $('#activity-body').html(activity_html);
// Format dates with moment before display.
$('.format-date').each(function() {
var date = $.trim($(this).html());
if (date != "") {
$(this).html(moment($(this).html()).format("ll"));
}
});
$("#date-slider").dateRangeSlider({
bounds: {min: new Date(2014, 6, 1),
max: new Date()},
defaultValues: {min: default_min, max: default_max},
arrows: false,
});
// Handler for the date range search button.
$('#slider-go-button').click(function() {
var dateValues = $("#date-slider").dateRangeSlider("values");
var min = Math.floor(dateValues.min.getTime()/1000);
var max = Math.floor(dateValues.max.getTime()/1000);
var url = "activity.php?";
if (window.ARG) {
url = url + window.ARG + "&";
}
url = url + "min=" + min + "&max=" + max;
window.location.replace(url);
});
var tablename = "#activity_table";
var searchname = "#activity_table_search";
var table = $(tablename)
.tablesorter({
theme : 'green',
//cssChildRow: "tablesorter-childRow",
// initialize zebra and filter widgets
widgets: ["zebra", "filter", "math"],
widgetOptions: {
// include child row content while filtering, if true
filter_childRows : true,
// include all columns in the search.
filter_anyMatch : true,
// class name applied to filter row and each input
filter_cssFilter : 'form-control',
// search from beginning
filter_startsWith : false,
// Set this option to false for case sensitive search
filter_ignoreCase : true,
// Only one search box.
filter_columnFilters : false,
// data-math attribute
math_data : 'math',
// ignore first column
math_ignore : [0],
// integers
math_mask : '',
}
});
// Target the $('.search') input using built in functioning
// this binds to the search using "search" and "keyup"
// Allows using filter_liveSearch or delayed search &
// pressing escape to cancel the search
$.tablesorter.filter.bindSearch(table, $(searchname));
} }
$(document).ready(initialize); $(document).ready(initialize);
}); });
...@@ -10,7 +10,7 @@ require(window.APT_OPTIONS.configObject, ...@@ -10,7 +10,7 @@ require(window.APT_OPTIONS.configObject,
'js/lib/text!template/snapshot-help.html', 'js/lib/text!template/snapshot-help.html',
'js/lib/text!template/oneonly-modal.html', 'js/lib/text!template/oneonly-modal.html',
'js/lib/text!template/approval-modal.html', 'js/lib/text!template/approval-modal.html',
'jquery-ui', 'contextmenu'], 'contextmenu'],
function (_, sup, moment, marked, UriTemplate, ShowImagingModal, function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
ShowExtendModal, statusString, waitwaitString, oopsString, ShowExtendModal, statusString, waitwaitString, oopsString,
registerString, terminateString, registerString, terminateString,
......
...@@ -7,6 +7,15 @@ function (sup, moment) ...@@ -7,6 +7,15 @@ function (sup, moment)
function initialize() function initialize()
{ {
window.APT_OPTIONS.initialize(sup); window.APT_OPTIONS.initialize(sup);
var default_min = new Date(2014, 6, 1);
var default_max = new Date();
if (window.MIN) {
default_min = new Date(window.MIN * 1000);
}
if (window.MAX) {
default_max = new Date(window.MAX * 1000);
}
// Format dates with moment before display. // Format dates with moment before display.
$('.format-date').each(function() { $('.format-date').each(function() {
...@@ -16,8 +25,23 @@ function (sup, moment) ...@@ -16,8 +25,23 @@ function (sup, moment)
.format("MMM Do, h:mm a")); .format("MMM Do, h:mm a"));
} }
}); });
$("#date-slider").dateRangeSlider({
bounds: {min: new Date(2014, 6, 1),
max: new Date()},
defaultValues: {min: default_min, max: default_max},
arrows: false,
});
InitTable("uid"); InitTable("uid");
InitTable("pid"); InitTable("pid");
// Handler for the date range search button.
$('#slider-go-button').click(function() {
var dateValues = $("#date-slider").dateRangeSlider("values");
var min = Math.floor(dateValues.min.getTime()/1000);
var max = Math.floor(dateValues.max.getTime()/1000);
window.location.replace("sumstats.php?min=" + min +
"&max=" + max);
});
} }
function InitTable(name) function InitTable(name)
......
...@@ -26,8 +26,8 @@ include("defs.php3"); ...@@ -26,8 +26,8 @@ include("defs.php3");
include_once("geni_defs.php"); include_once("geni_defs.php");
chdir("apt"); chdir("apt");
include("quickvm_sup.php"); include("quickvm_sup.php");
include("profile_defs.php"); include_once("profile_defs.php");
include("instance_defs.php"); include_once("instance_defs.php");
$page_title = "My Experiments"; $page_title = "My Experiments";
$dblink = GetDBLink("sa"); $dblink = GetDBLink("sa");
...@@ -70,7 +70,10 @@ if ($all && ISADMIN()) { ...@@ -70,7 +70,10 @@ if ($all && ISADMIN()) {
$query_result1 = $query_result1 =
DBQueryFatal("select a.*,s.expires,s.hrn,u.email, ". DBQueryFatal("select a.*,s.expires,s.hrn,u.email, ".
" (UNIX_TIMESTAMP(now()) > ". " (UNIX_TIMESTAMP(now()) > ".
" UNIX_TIMESTAMP(s.expires)) as expired ". " UNIX_TIMESTAMP(s.expires)) as expired, ".
" truncate(a.physnode_count * ".
" ((UNIX_TIMESTAMP(now()) - ".
" UNIX_TIMESTAMP(a.created)) / 3600.0),2) as phours ".
" from apt_instances as a ". " from apt_instances as a ".
"left join geni.geni_slices as s on ". "left join geni.geni_slices as s on ".
" s.uuid=a.slice_uuid ". " s.uuid=a.slice_uuid ".
...@@ -81,7 +84,10 @@ else { ...@@ -81,7 +84,10 @@ else {
$query_result1 = $query_result1 =
DBQueryFatal("select a.*,s.expires,s.hrn,u.email, ". DBQueryFatal("select a.*,s.expires,s.hrn,u.email, ".
" (UNIX_TIMESTAMP(now()) > ". " (UNIX_TIMESTAMP(now()) > ".
" UNIX_TIMESTAMP(s.expires)) as expired ". " UNIX_TIMESTAMP(s.expires)) as expired, ".
" truncate(a.physnode_count * ".
" ((UNIX_TIMESTAMP(now()) - ".
" UNIX_TIMESTAMP(a.created)) / 3600.0),2) as phours ".
" from apt_instances as a ". " from apt_instances as a ".
"left join geni.geni_slices as s on ". "left join geni.geni_slices as s on ".
" s.uuid=a.slice_uuid ". " s.uuid=a.slice_uuid ".
...@@ -91,7 +97,10 @@ else { ...@@ -91,7 +97,10 @@ else {
$query_result2 = $query_result2 =
DBQueryFatal("select distinct a.*,s.expires,s.hrn,u.email, ". DBQueryFatal("select distinct a.*,s.expires,s.hrn,u.email, ".
" (UNIX_TIMESTAMP(now()) > ". " (UNIX_TIMESTAMP(now()) > ".
" UNIX_TIMESTAMP(s.expires)) as expired ". " UNIX_TIMESTAMP(s.expires)) as expired, ".
" truncate(a.physnode_count * ".
" ((UNIX_TIMESTAMP(now()) - ".
" UNIX_TIMESTAMP(a.created)) / 3600.0),2) as phours ".
" from apt_instances as a ". " from apt_instances as a ".
"left join geni.geni_slices as s on ". "left join geni.geni_slices as s on ".
" s.uuid=a.slice_uuid ". " s.uuid=a.slice_uuid ".
...@@ -124,11 +133,10 @@ function SPITROWS($all, $name, $result) ...@@ -124,11 +133,10 @@ function SPITROWS($all, $name, $result)
} }
echo " <th>Project</th> echo " <th>Project</th>
<th>Status</th> <th>Status</th>
<th>Cluster</th>\n"; <th>Cluster</th>
if