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

Mostly a big clean up, moving code out of the old sup file,

and into the js files associated with the code.
parent 81642ef0
...@@ -56,6 +56,14 @@ $optargs = OptionalPageArguments("create", PAGEARG_STRING, ...@@ -56,6 +56,14 @@ $optargs = OptionalPageArguments("create", PAGEARG_STRING,
# #
if (isset($ajax_request)) { if (isset($ajax_request)) {
if ($ajax_method == "getprofile") { if ($ajax_method == "getprofile") {
#
# We require the UUID on this path, until proper permission
# checks are done; too easy to guess an index.
#
if (!IsValidUUID($ajax_argument)) {
SPITAJAX_ERROR(1, "Not a valid UUID: $ajax_argument");
exit();
}
$obj = Profile::Lookup($ajax_argument); $obj = Profile::Lookup($ajax_argument);
if (!$obj) { if (!$obj) {
SPITAJAX_ERROR(1, "No such profile $ajax_argument"); SPITAJAX_ERROR(1, "No such profile $ajax_argument");
...@@ -80,25 +88,42 @@ $profile_array = array(); ...@@ -80,25 +88,42 @@ $profile_array = array();
# add to the array now since it might not be public or belong to the user. # add to the array now since it might not be public or belong to the user.
# #
if (isset($profile)) { if (isset($profile)) {
if (preg_match("/^\w+\-\w+\-\w+\-\w+\-\w+$/", $profile)) { #
$obj = Profile::Lookup($profile); # Guest users must use the uuid, but logged in users may use the
if (! $obj) { # internal index.
SPITHEADER(1); #
SPITUSERERROR("No such profile: $profile"); if (! ($this_user || IsValidUUID($profile))) {
echo "<script src='js/lib/require.js' data-main='js/null'> SPITUSERERROR("Illegal profile for guest user: $profile");
</script>\n"; exit();
SPITFOOTER(); }
} $obj = Profile::Lookup($profile);
if (! $obj) {
SPITUSERERROR("No such profile: $profile");
exit();
}
if (IsValidUUID($profile)) {
$profile_array[$profile] = $obj->name(); $profile_array[$profile] = $obj->name();
$profilename = $obj->name(); $profilename = $obj->name();
} }
else { else {
$profilename = $profile; #
# Must be public or belong to user.
#
if (! ($obj->ispublic() ||
$obj->creator_idx == $this_user->uid_idx())) {
SPITUSERERROR("No permission to use profile: $profile");
exit();
}
$profile = $obj->uuid();
$profile_array[$profile] = $obj->name();
$profilename = $obj->name();
} }
} }
# #
# Still do this cause of non-secret URLs. This needs more work. # Find all the public and user profiles. We use the UUID instead of
# indicies cause we do not want to leak internal DB state to guest
# users.
# #
$query_result = $query_result =
DBQueryFatal("select * from apt_profiles ". DBQueryFatal("select * from apt_profiles ".
......
...@@ -10,14 +10,14 @@ function ($, sup) ...@@ -10,14 +10,14 @@ function ($, sup)
function initialize() function initialize()
{ {
window.APT_OPTIONS.initialize(sup); window.APT_OPTIONS.initialize(sup);
sup.UpdateProfileSelection($('#profile_name li[value = ' + window.PROFILE + ']'));
$('#quickvm_topomodal').on('hidden.bs.modal', function() { $('#quickvm_topomodal').on('hidden.bs.modal', function() {
sup.ShowProfileList($('.current')) ShowProfileList($('.current'))
}); });
$('button#reset-form').click(function (event) { $('button#reset-form').click(function (event) {
event.preventDefault(); event.preventDefault();
sup.resetForm($('#quickvm_form')); resetForm($('#quickvm_form'));
}); });
$('button#profile').click(function (event) { $('button#profile').click(function (event) {
event.preventDefault(); event.preventDefault();
...@@ -25,13 +25,92 @@ function ($, sup) ...@@ -25,13 +25,92 @@ function ($, sup)
}); });
$('li.profile-item').click(function (event) { $('li.profile-item').click(function (event) {
event.preventDefault(); event.preventDefault();
sup.ShowProfileList(event.target); ShowProfileList(event.target);
}); });
$('button#showtopo_select').click(function (event) { $('button#showtopo_select').click(function (event) {
event.preventDefault(); event.preventDefault();
sup.UpdateProfileSelection($('.selected')); UpdateProfileSelection($('.selected'));
sup.HideModal('#quickvm_topomodal'); sup.HideModal('#quickvm_topomodal');
}); });
UpdateProfileSelection($('#profile_name li[value = ' +
window.PROFILE + ']'));
}
function resetForm($form) {
$form.find('input:text, input:password, select, textarea').val('');
}
function UpdateProfileSelection(selectedElement)
{
var profile_name = $(selectedElement).text();
var profile_value = $(selectedElement).attr('value');
$('#selected_profile').attr('value', profile_value);
$('#selected_profile_text').html("" + profile_name);
if (!$(selectedElement).hasClass('current')) {
$('#profile_name li').each(function() {
$(this).removeClass('current');
});
$(selectedElement).addClass('current');
}
ShowProfileList(selectedElement);
}
function ShowProfileList(selectedElement)
{
var profile = $(selectedElement).attr('value');
if (!$(selectedElement).hasClass('selected')) {
$('#profile_name li').each(function() {
$(this).removeClass('selected');
});
$(selectedElement).addClass('selected');
}
var callback = function(json) {
console.info(json.value);
if (json.code) {
alert("Could not get profile: " + json.value);
return;
}
var xmlDoc = $.parseXML(json.value.rspec);
var xml = $(xmlDoc);
var topo = sup.ConvertManifestToJSON(profile, xml);
$('#showtopo_title').html("<h3>" + json.value.name + "</h3>");
/*
* We now use the desciption from inside the rspec, unless there
* is none, in which case look to see if the we got one in the
* rpc reply, which we will until all profiles converted over to
* new format rspecs.
*/
var description = null;
$(xml).find("rspec_tour").each(function() {
$(this).find("description").each(function() {
description = $(this).text();
});
});
if (!description) {
if (json.value.description != "") {
description = json.value.description;
}
else {
description = "Hmm, no description for this profile";
}
}
$('#showtopo_description').html(description);
$('#selected_profile_description').html(description);
sup.maketopmap("#showtopo_div",
($("#showtopo_div").outerWidth()),
300, topo, null);
}
var $xmlthing = sup.CallMethod("getprofile", null, 0, profile);
$xmlthing.done(callback);
} }
$(document).ready(initialize); $(document).ready(initialize);
......
...@@ -39,7 +39,6 @@ function ($, sup) ...@@ -39,7 +39,6 @@ function ($, sup)
$('#profile_rspec_textarea').val(content); $('#profile_rspec_textarea').val(content);
ExtractFromRspec(xml); ExtractFromRspec(xml);
//ShowRspecTopo(xml);
}; };
reader.readAsText(this.files[0]); reader.readAsText(this.files[0]);
}); });
...@@ -205,9 +204,10 @@ function ($, sup) ...@@ -205,9 +204,10 @@ function ($, sup)
removeLast: true removeLast: true
}, },
columns: [ columns: [
{ name: 'Type', display: 'Type', type: 'text', { name: 'Type', display: 'Type', type: 'select',
ctrlAttr: { maxlength: 100 }, ctrlAttr: { maxlength: 100 },
ctrlCss: { width: '80px'} ctrlCss: { width: '80px'},
ctrlOptions: ["node", "link"],
}, },
{ name: 'ID', display: 'ID', type: 'text', { name: 'ID', display: 'ID', type: 'text',
ctrlAttr: { maxlength: 100, ctrlAttr: { maxlength: 100,
...@@ -221,6 +221,9 @@ function ($, sup) ...@@ -221,6 +221,9 @@ function ($, sup)
initData: steps initData: steps
}); });
}); });
// Show the steps area.
$('#profile_steps_div').removeClass("hidden");
} }
// //
...@@ -376,7 +379,7 @@ function ($, sup) ...@@ -376,7 +379,7 @@ function ($, sup)
// Subtract -2 cause of the border. // Subtract -2 cause of the border.
sup.maketopmap("#showtopo_nopicker", sup.maketopmap("#showtopo_nopicker",
($("#showtopo_nopicker").outerWidth() - 2), ($("#showtopo_nopicker").outerWidth() - 2),
300, topo); 300, topo, null);
} }
$(document).ready(initialize); $(document).ready(initialize);
......
...@@ -63,7 +63,7 @@ function ($, sup) ...@@ -63,7 +63,7 @@ function ($, sup)
// Subtract -2 cause of the border. // Subtract -2 cause of the border.
sup.maketopmap("#showtopo_nopicker", sup.maketopmap("#showtopo_nopicker",
($("#showtopo_nopicker").outerWidth() - 2), ($("#showtopo_nopicker").outerWidth() - 2),
300, topo); 300, topo, null);
}; };
var $xmlthing = sup.CallMethod("getprofile", null, 0, profile); var $xmlthing = sup.CallMethod("getprofile", null, 0, profile);
$xmlthing.done(callback); $xmlthing.done(callback);
......
define(['jquery', 'd3', 'dateformat', 'marked'], define(['jquery', 'd3', 'dateformat', 'marked'],
function ($, d3) { function ($, d3) {
var myuuid = null;
function ShowModal(which) function ShowModal(which)
{ {
// console.log('Showing modal ' + which); // console.log('Showing modal ' + which);
...@@ -37,606 +35,13 @@ function CallMethod(method, callback, uuid, arg) ...@@ -37,606 +35,13 @@ function CallMethod(method, callback, uuid, arg)
}); });
} }
function GetStatus(uuid) function maketopmap(divname, width, height, json, sshcallback)
{
var callback = function(json) {
StatusWatchCallBack(uuid, json);
}
var $xmlthing = CallMethod("status", null, uuid, null);
$xmlthing.done(callback);
}
// Set up a timer to watch the status.
function StartStatusWatch(uuid)
{
setTimeout(function f() { GetStatus(uuid) }, 5000);
}
// Call back for above.
function StatusWatchCallBack(uuid, json)
{
// Check to see if the static variable has been initialized
if (typeof StatusWatchCallBack.laststatus == 'undefined') {
// It has not... perform the initilization
StatusWatchCallBack.laststatus = "";
}
var status = json.value;
if (json.code) {
status = "terminated";
}
if (status != StatusWatchCallBack.laststatus) {
status_html = status;
var bgtype = "";
var statustext = "Please wait while we get your experiment ready";
if (status == 'provisioned') {
$("#quickvm_progress_bar").width("66%");
}
else if (status == 'ready') {
bgtype = "bg-success";
statustext = "Your experiment is ready!";
status_html = "<font color=green>ready</font>";
if ($("#quickvm_progress").length) {
$("#quickvm_progress").removeClass("progress-striped");
$("#quickvm_progress").removeClass("active");
$("#quickvm_progress").addClass("progress-bar-success");
$("#quickvm_progress_bar").width("100%");
}
$("#terminate_button").prop("disabled", false);
$("#extend_button").prop("disabled", false);
ShowTopo(uuid);
}
else if (status == 'failed') {
bgtype = "bg-danger";
statustext = "Something went wrong, sorry! We've been notified.";
status_html = "<font color=red>failed</font>";
if ($("#quickvm_progress").length) {
$("#quickvm_progress").removeClass("progress-striped");
$("#quickvm_progress").removeClass("active");
$("#quickvm_progress").addClass("progress-bar-danger");
$("#quickvm_progress_bar").width("100%");
}
$("#terminate_button").prop("disabled", false);
}
else if (status == 'terminating' || status == 'terminated') {
status_html = "<font color=red>" + status + "</font>";
$("#terminate_button").prop("disabled", true);
$("#extend_button").prop("disabled", true);
StartCountdownClock.stop = 0;
}
$("#statusmessage").html(statustext);
$("#statusmessage-container")
.removeClass('bg-success bg-danger')
.addClass(bgtype);
$("#quickvm_status").html(status_html);
}
StatusWatchCallBack.laststatus = status;
if (! (status == 'terminating' || status == 'terminated')) {
setTimeout(function f() { GetStatus(uuid) }, 5000);
}
}
function Terminate(uuid, url)
{
var callback = function(json) {
window.location.replace(url);
}
$("#terminate_button").prop("disabled", true);
$("#extend_button").prop("disabled", true);
HideModal('#terminate_modal');
var $xmlthing = CallMethod("terminate", null, uuid, null);
$xmlthing.done(callback);
}
function ShowTopo(uuid)
{
var callback = function(json) {
console.info(json.value);
var xmlDoc = $.parseXML(json.value);
var xml = $(xmlDoc);
var topo = ConvertManifestToJSON(null, xml);
console.info(json.value);
// Suck the instructions out of the tour and put them into
// the Usage area.
$(xml).find("rspec_tour").each(function() {
$(this).find("instructions").each(function() {
var marked = require('marked');
marked.setOptions({"sanitize" : true});
var text = $(this).text();
// Stick the text in
$('#instructions_text').html(marked(text));
// Make the div visible.
$('#instructions_panel').removeClass("invisible");
});
});
// Find all of the nodes, and put them into the list tab.
// Clear current table.
$('#listview_table > tbody').html("");
$(xml).find("node").each(function() {
var node = $(this).attr("client_id");
var login = $(this).find("login");
var href = "n/a";
var ssh = "n/a";
if (login.length) {
var user = login.attr("username");
var host = login.attr("hostname");
var port = login.attr("port");
var url = "ssh://" + user + "@" + host + ":" + port + "/";
href = "<a href='" + url + "'>" + url + "</a>";
console.info(url);
var hostport = host + ":" + port;
ssh = "<button class='btn btn-primary btn-xs' " +
" id='" + "sshbutton_" + node + "' " +
" type='button'>" +
" <span class='glyphicon glyphicon-log-in'><span>" +
" </button>";
console.info(ssh);
// Use this to attach handlers to things that do not exist.
$('#listview_table').off('click', '#sshbutton_' + node);
$('#listview_table').on('click',
'#sshbutton_' + node, function () {
NewSSHTab(hostport, node);
});
}
$('#listview_table > tbody:last').append(
'<tr><td>' + node + '</td><td>' + ssh + '</td><td>' +
href + '</td></tr>'
);
});
$("#showtopo_container").removeClass("invisible");
// Subtract -2 cause of the border.
maketopmap("#showtopo_statuspage",
$("#showtopo_statuspage").outerWidth() - 2,
300, topo);
}
console.info(uuid);
var $xmlthing = CallMethod("manifest", null, uuid, null);
$xmlthing.done(callback);
}
function UpdateProfileSelection(selectedElement)
{
var profile_name = $(selectedElement).text();
var profile_value = $(selectedElement).attr('value');
$('#selected_profile').attr('value', profile_value);
$('#selected_profile_text').html("" + profile_name);
if (!$(selectedElement).hasClass('current')) {
$('#profile_name li').each(function() {
$(this).removeClass('current');
});
$(selectedElement).addClass('current');
}
ShowProfileList(selectedElement);
}
function ShowProfileList(selectedElement)
{
var profile = $(selectedElement).attr('value');
if (!$(selectedElement).hasClass('selected')) {
$('#profile_name li').each(function() {
$(this).removeClass('selected');
});
$(selectedElement).addClass('selected');
}
var callback = function(json) {
console.info(json.value);
if (json.code) {
alert("Could not get profile: " + json.value);
return;
}
var xmlDoc = $.parseXML(json.value.rspec);
var xml = $(xmlDoc);
var topo = ConvertManifestToJSON(profile, xml);
$('#showtopo_title').html("<h3>" + json.value.name + "</h3>");
/*
* We now use the desciption from inside the rspec, unless there
* is none, in which case look to see if the we got one in the
* rpc reply, which we will until all profiles converted over to
* new format rspecs.
*/
var description = null;
$(xml).find("rspec_tour").each(function() {
$(this).find("description").each(function() {
description = $(this).text();
});
});
if (!description) {
if (json.value.description != "") {
description = json.value.description;
}
else {
description = "Hmm, no description for this profile";
}
}
$('#showtopo_description').html(description);
$('#selected_profile_description').html(description);
maketopmap("#showtopo_div",
($("#showtopo_div").outerWidth()),
300, topo);
}
var $xmlthing = CallMethod("getprofile", null, 0, profile);
$xmlthing.done(callback);
}
function Setsshurl(uuid)
{
var callback = function(json) {
var xmlDoc = $.parseXML(json.value);
var xml = $(xmlDoc);
var login = $(xml).find("login");
var user = login.attr("username");
var host = login.attr("hostname");
var port = login.attr("port");
var url = "ssh://" + user + "@" + host + ":" + port + "/";
var href = "<a href='" + url + "'>" + url + "</a>";
console.info(url);
$("#quickvm_sshurl").html(href);
}
var $xmlthing = CallMethod("manifest", null, uuid, null);
$xmlthing.done(callback);
}
//
// Request experiment extension.
//
function RequestExtension(uuid)
{
var reason = $("#why_extend").val();
console.info(reason);
if (reason.length < 30) {
alert("Your reason is too short! Say more please.");
return;
}
var callback = function(json) {
console.info(json.value);
if (json.code) {
if (json.code < 0) {
alert("Could not extend experiment. Please try again later");
}
else {
alert("Could not extend experiment: " + json.value);
}
return;
}
$("#quickvm_expires").html(json.value);
// Reset the countdown clock.
StartCountdownClock.reset = json.value;
}
var $xmlthing = CallMethod("request_extension", null, uuid, reason);
HideModal('#extend_modal');
$xmlthing.done(callback);
}
function Extend(uuid)
{
var code = $("#extend_code").val();