Commit cd405440 authored by Leigh Stoller's avatar Leigh Stoller

Implement part of issue #339; a page to see all experiment errors.

parent a4d4ceca
...@@ -175,6 +175,106 @@ function Do_ExperimentList() ...@@ -175,6 +175,106 @@ function Do_ExperimentList()
SPITAJAX_RESPONSE($results); SPITAJAX_RESPONSE($results);
} }
function Do_ExperimentErrors()
{
global $this_user, $urn_mapping, $geni_response_codes;
global $ajax_args;
$clause = "";
$results = array();
if (CheckPageArgs()) {
return;
}
if (isset($ajax_args["stamp"]) && TBvalid_integer($ajax_args["stamp"])) {
$stamp = $ajax_args["stamp"];
$clause = "where UNIX_TIMESTAMP(f.created) <= $stamp";
}
$query_result =
DBQueryFatal("select f.name,exitcode,f.created,f.public_url,f.uuid,".
" IF(i.uuid,1,0) as active,f.exitmessage, ".
" p.uuid as profile_uuid,p.name as profile_name, ".
" IF(i.uuid,i.aggregate_urn,h.aggregate_urn) ".
" as aggregate_urn, ".
" f.slice_uuid,f.logfileid,f.creator ".
"from apt_instance_failures as f ".
"left join apt_instances as i on ".
" i.uuid=f.uuid ".
"left join apt_instance_history as h on ".
" h.uuid=f.uuid ".
"left join apt_profiles as p on ".
" p.profileid=f.profile_id ".
$clause . " " .
"order by f.created desc limit 25");
while ($row = mysql_fetch_array($query_result)) {
$name = $row["name"];
$exitcode = $row["exitcode"];
$url = $row["public_url"];
$logfileid = $row["logfileid"];
$active = $row["active"] ? 1 : 0;
$uuid = $row["uuid"];
$created = DateStringGMT($row["created"]);
$creator = $row["creator"];
$message = $row["exitmessage"];
$reason = $exitcode;
$slice_uuid = $row["slice_uuid"];
$profile_uuid = $row["profile_uuid"];
$profile_name = $row["profile_name"];
$aggregate_urn= $row["aggregate_urn"];
$cluster = "N/A";
if ($exitcode >= 0 && $exitcode <= count($geni_response_codes)) {
$reason = $geni_response_codes[$exitcode];
}
elseif ($exitcode == GENIRESPONSE_STITCHER_ERROR) {
$reason = "Stitcher Failed";
}
if ($aggregate_urn && $aggregate_urn != "") {
$cluster = $urn_mapping[$aggregate_urn];
}
#
# Ick. If the url is for the showslicepub link, we have a problem;
# the link is good only while the slice is alive. After that, we have
# to use a private url (which is okay, cause only admins are going
# to see it and be able to use it).
#
if (ISFOREIGN_ADMIN()) {
$url = null;
}
elseif (!$url) {
#
# If there is a log file, show that instead.
#
if ($logfileid) {
$url = $TBBASE . "/" .
CreateURL("spewlogfile", "logfile", $logfileid);
}
}
elseif (preg_match("/^(https:.*)\/showslicepub/", $url, $matches)) {
if (ISADMIN()) {
$url = $matches[1] . "/showslicelogs.php?slice_uuid=".
$slice_uuid;
}
else {
$url = null;
}
}
$results[$uuid] = array("name" => $name,
"uuid" => $uuid,
"exitcode" => $exitcode,
"active" => $active,
"created" => $created,
"creator" => $creator,
"reason" => $reason,
"message" => $message,
"url" => $url,
"cluster" => $cluster,
"profile_uuid" => $profile_uuid,
"profile_name" => $profile_name);
}
SPITAJAX_RESPONSE($results);
}
# Local Variables: # Local Variables:
# mode:php # mode:php
# End: # End:
......
<?php
#
# Copyright (c) 2000-2017 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
# This file is part of the Emulab network testbed software.
#
# This file is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or (at
# your option) any later version.
#
# This file is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this file. If not, see <http://www.gnu.org/licenses/>.
#
# }}}
#
chdir("..");
include("defs.php3");
include_once("geni_defs.php");
chdir("apt");
include("quickvm_sup.php");
$page_title = "Errors";
#
# Get current user.
#
RedirectSecure();
$this_user = CheckLoginOrRedirect();
$isadmin = (ISADMIN() ? 1 : 0);
$isfadmin = (ISFOREIGN_ADMIN() ? 1 : 0);
if (! (ISADMIN() || ISFOREIGN_ADMIN())) {
SPITUSERERROR("You do not have permission to view this page");
}
SPITHEADER(1);
echo "<div id='page-body'>
<div id='errors-div'></div>
<div id='waitwait_div'></div>
<div id='oops_div'></div>
</div>\n";
echo "<script type='text/javascript'>\n";
echo " window.ISADMIN = $isadmin;\n";
echo " window.ISFADMIN = $isfadmin;\n";
echo "</script>\n";
echo "<script src='js/lib/jquery-2.0.3.min.js'></script>\n";
REQUIRE_UNDERSCORE();
REQUIRE_SUP();
REQUIRE_MOMENT();
SPITREQUIRE("js/instance-errors.js");
AddTemplateList(array("instance-errors", "waitwait-modal", "oops-modal"));
SPITFOOTER();
?>
$(function ()
{
'use strict';
var templates = APT_OPTIONS.fetchTemplateList(['instance-errors',
'waitwait-modal', 'oops-modal']);
var template = _.template(templates['instance-errors']);
var waitwait = templates['waitwait-modal'];
var oops = templates['oops-modal'];
var page = 0;
var pages = [];
var earliest = null; // Earliest (last) on the page.
function initialize()
{
window.APT_OPTIONS.initialize(sup);
$('#waitwait_div').html(waitwait);
$('#oops_div').html(oops);
LoadErrors();
}
function LoadErrors(earliest)
{
var callback = function(json) {
console.log(json);
if (json.code) {
console.log("Could not get dashboard data: " + json.value);
return;
}
if (earliest !== undefined) {
page++;
}
pages[page] = json.value;
RenderErrors(json.value);
};
var args = null;
if (earliest !== undefined) {
args = {"stamp" : earliest};
}
console.info(args);
var xmlthing = sup.CallServerMethod(null, "experiments",
"ExperimentErrors", args);
xmlthing.done(callback);
}
function RenderErrors(errors)
{
var html = template({"errors" : errors,
"isadmin" : window.ISADMIN,
"isfadmin" : window.ISFADMIN});
$('#errors-div').html(html);
$('#page-number').html(page + 1);
// Format dates with moment before display.
$('.format-date').each(function() {
var date = $.trim($(this).html());
if (date != "") {
$(this).html(moment($(this).html())
.format("ddd h:mm A"));
}
});
$('[data-toggle="popover"]').popover({
trigger: 'hover',
placement: 'auto',
html: true,
content: function () {
var uuid = $(this).data("uuid");
var html = "<code style='white-space: pre-wrap'>" +
errors[uuid].message + "</code>";
return html;
}
});
$('#next-page').click(function (event) {
event.preventDefault();
LoadErrors(earliest);
});
$('#prev-page').click(function (event) {
event.preventDefault();
if (page > 0) {
page--;
RenderErrors(pages[page]);
}
});
// Remember the last date in the range.
var keys = Object.keys(errors);
var uuid = keys[keys.length - 1];
earliest = moment(errors[uuid].created).valueOf() / 1000;
// Enable previous button after page 0.
if (page > 0) {
$('#prev-page').removeAttr("disabled");
}
else {
$('#prev-page').attr("disabled");
}
}
$(document).ready(initialize);
});
...@@ -384,7 +384,9 @@ $routing = array("myprofiles" => ...@@ -384,7 +384,9 @@ $routing = array("myprofiles" =>
array("file" => "experiments.ajax", array("file" => "experiments.ajax",
"guest" => false, "guest" => false,
"methods" => array("ExperimentList" => "methods" => array("ExperimentList" =>
"Do_ExperimentList")), "Do_ExperimentList",
"ExperimentErrors" =>
"Do_ExperimentErrors")),
"approve-projects" => "approve-projects" =>
array("file" => "approve-projects.ajax", array("file" => "approve-projects.ajax",
"guest" => false, "guest" => false,
......
<div class='row'>
<div class='col-sm-12'>
<div class='panel panel-default' id='errors-panel'>
<div class="panel-heading">
<h5><center>Recent Errors (Page <span id="page-number">0</span>)
</center></h5>
</div>
<div class='panel-body panel-body-dashboard'>
<table class="table table-condensed table-bordered table-dashboard">
<thead>
<tr>
<th>Name</th>
<th>Creator</th>
<th>When</th>
<th>Profile</th>
<th>Cluster</th>
<th>Reason (Code)</th>
<th>Log</th>
</tr>
</thead>
<tbody>
<% _.each(errors, function(value, key) { %>
<tr>
<% if (value.active) { %>
<td><a href="status.php?uuid=<%- value.uuid %>">
<%- value.name %></a></td>
<% }else { %>
<td><%- value.name %></td>
<% } %>
<td><a href="user-dashboard.php?user=<%- value.creator %>">
<%- value.creator %></a></td>
<td class="format-date"><%- value.created %></td>
<td><a href="show-profile.php?uuid=<%- value.profile_uuid %>">
<%- value.profile_name %></a></td>
<td><%- value.cluster %></td>
<% if (value.message && value.message != "") { %>
<td><span style="text-decoration: underline;"
data-toggle='popover'
data-delay='{"hide":100, "show":500}'
data-html='true'
data-uuid="<%- value.uuid %>"
data-content=""><%- value.reason %></span></td>
<% } else { %>
<td><%- value.reason %></td>
<% } %>
<% if (value.url) { %>
<td><a href="<%- value.url%>" target="_blank">Log</a></td>
<% } else { %>
<td>N/A</td>
<% } %>
</tr>
<% }); %>
</tbody>
</table>
<center>
<button id='prev-page' style="margin-right: 10px;" disabled
class='btn btn-primary btn-sm'>Prev</button>
<button id='next-page'
class='btn btn-primary btn-sm'>Next</button>
</center>
</div>
</div>
</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