All new accounts created on Gitlab now require administrator approval. If you invite any collaborators, please let Flux staff know so they can approve the accounts.

Commit cd405440 authored by Leigh B Stoller's avatar Leigh B Stoller

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

parent a4d4ceca
......@@ -175,6 +175,106 @@ function Do_ExperimentList()
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:
# mode:php
# 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" =>
array("file" => "experiments.ajax",
"guest" => false,
"methods" => array("ExperimentList" =>
"Do_ExperimentList")),
"Do_ExperimentList",
"ExperimentErrors" =>
"Do_ExperimentErrors")),
"approve-projects" =>
array("file" => "approve-projects.ajax",
"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