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,
#
if (isset($ajax_request)) {
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);
if (!$obj) {
SPITAJAX_ERROR(1, "No such profile $ajax_argument");
......@@ -80,25 +88,42 @@ $profile_array = array();
# add to the array now since it might not be public or belong to the user.
#
if (isset($profile)) {
if (preg_match("/^\w+\-\w+\-\w+\-\w+\-\w+$/", $profile)) {
$obj = Profile::Lookup($profile);
if (! $obj) {
SPITHEADER(1);
SPITUSERERROR("No such profile: $profile");
echo "<script src='js/lib/require.js' data-main='js/null'>
</script>\n";
SPITFOOTER();
}
#
# Guest users must use the uuid, but logged in users may use the
# internal index.
#
if (! ($this_user || IsValidUUID($profile))) {
SPITUSERERROR("Illegal profile for guest user: $profile");
exit();
}
$obj = Profile::Lookup($profile);
if (! $obj) {
SPITUSERERROR("No such profile: $profile");
exit();
}
if (IsValidUUID($profile)) {
$profile_array[$profile] = $obj->name();
$profilename = $obj->name();
}
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 =
DBQueryFatal("select * from apt_profiles ".
......
......@@ -10,14 +10,14 @@ function ($, sup)
function initialize()
{
window.APT_OPTIONS.initialize(sup);
sup.UpdateProfileSelection($('#profile_name li[value = ' + window.PROFILE + ']'));
$('#quickvm_topomodal').on('hidden.bs.modal', function() {
sup.ShowProfileList($('.current'))
ShowProfileList($('.current'))
});
$('button#reset-form').click(function (event) {
event.preventDefault();
sup.resetForm($('#quickvm_form'));
resetForm($('#quickvm_form'));
});
$('button#profile').click(function (event) {
event.preventDefault();
......@@ -25,13 +25,92 @@ function ($, sup)
});
$('li.profile-item').click(function (event) {
event.preventDefault();
sup.ShowProfileList(event.target);
ShowProfileList(event.target);
});
$('button#showtopo_select').click(function (event) {
event.preventDefault();
sup.UpdateProfileSelection($('.selected'));
UpdateProfileSelection($('.selected'));
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);
......
......@@ -39,7 +39,6 @@ function ($, sup)
$('#profile_rspec_textarea').val(content);
ExtractFromRspec(xml);
//ShowRspecTopo(xml);
};
reader.readAsText(this.files[0]);
});
......@@ -205,9 +204,10 @@ function ($, sup)
removeLast: true
},
columns: [
{ name: 'Type', display: 'Type', type: 'text',
{ name: 'Type', display: 'Type', type: 'select',
ctrlAttr: { maxlength: 100 },
ctrlCss: { width: '80px'}
ctrlCss: { width: '80px'},
ctrlOptions: ["node", "link"],
},
{ name: 'ID', display: 'ID', type: 'text',
ctrlAttr: { maxlength: 100,
......@@ -221,6 +221,9 @@ function ($, sup)
initData: steps
});
});
// Show the steps area.
$('#profile_steps_div').removeClass("hidden");
}
//
......@@ -376,7 +379,7 @@ function ($, sup)
// Subtract -2 cause of the border.
sup.maketopmap("#showtopo_nopicker",
($("#showtopo_nopicker").outerWidth() - 2),
300, topo);
300, topo, null);
}
$(document).ready(initialize);
......
......@@ -63,7 +63,7 @@ function ($, sup)
// Subtract -2 cause of the border.
sup.maketopmap("#showtopo_nopicker",
($("#showtopo_nopicker").outerWidth() - 2),
300, topo);
300, topo, null);
};
var $xmlthing = sup.CallMethod("getprofile", null, 0, profile);
$xmlthing.done(callback);
......
define(['jquery', 'd3', 'dateformat', 'marked'],
function ($, d3) {
var myuuid = null;
function ShowModal(which)
{
// console.log('Showing modal ' + which);
......@@ -37,606 +35,13 @@ function CallMethod(method, callback, uuid, arg)
});
}
function GetStatus(uuid)
{
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();
console.info(code);
if (code == "") {
return;
}
var callback = function(json) {
console.info(json.value);
}
var $xmlthing = CallMethod("extend", null, uuid, code);
HideModal('#extend_modal');
$xmlthing.done(callback);
}
//
// Open up a window to the account registration page.
//
function RegisterAccount(uid, email)
{
HideModal('#register_modal');
var url = "signup.php?uid=" + uid + "&email=" + email + "";
var win = window.open(url, '_blank');
win.focus();
}
function InitQuickVM(uuid, slice_expires)
{
// Use an unload event to terminate any shells.
$(window).bind("unload", function() {
console.info("Unload function called");
$('#quicktabs_content div').each(function () {
var $this = $(this);
// Skip the main profile tab
if ($this.attr("id") == "profile") {
return;
}
var tabname = $this.attr("id");
// Trigger the custom event.
$("#" + tabname).trigger("killssh");
});
});
$(window).bind("beforeunload", function() {
console.info("BeforeUnload function called");
});
$(window).bind("pagehide", function() {
console.info("Pagehide function called");
});
StartCountdownClock(slice_expires);
GetStatus(uuid);
myuuid = uuid;
}
function resetForm($form) {
$form.find('input:text, input:password, select, textarea').val('');
}
function StartSSH(id, authobject)
{
var jsonauth = $.parseJSON(authobject);