Commit 8e04440d authored by Leigh Stoller's avatar Leigh Stoller

Add "Instantiate as Guest" to profile page. This logs out the user,

and instantiates the profile as a guest user, as for testing.
parent 3787dd35
......@@ -106,5 +106,86 @@ class Instance
$this->instance = mysql_fetch_array($query_result);
return 0;
}
#
# Class function to create a new Instance
#
function Instantiate($creator, $options, $args, &$errors) {
global $suexec_output, $suexec_output_array;
# So we can look up the slice after the backend creates it.
$uuid = NewUUID();
#
# Generate a temporary file and write in the XML goo.
#
$xmlname = tempnam("/tmp", "quickvm");
if (! $xmlname) {
TBERROR("Could not create temporary filename", 0);
$errors["error"] = "Transient error(1); please try again later.";
return null;
}
elseif (! ($fp = fopen($xmlname, "w"))) {
TBERROR("Could not open temp file $xmlname", 0);
$errors["error"] = "Transient error(2); please try again later.";
return null;
}
else {
fwrite($fp, "<quickvm>\n");
foreach ($args as $name => $value) {
fwrite($fp, "<attribute name=\"$name\">");
fwrite($fp, " <value>" . htmlspecialchars($value) .
"</value>");
fwrite($fp, "</attribute>\n");
}
fwrite($fp, "</quickvm>\n");
fclose($fp);
chmod($xmlname, 0666);
}
#
# This option is used to tell the backend that it is okay to look
# in the emulab users table.
#
$options .= ($creator ? " -l" : "");
if (isset($_SERVER['REMOTE_ADDR'])) {
putenv("REMOTE_ADDR=" . $_SERVER['REMOTE_ADDR']);
}
$retval = SUEXEC("nobody", "nobody",
"webquickvm $options -u $uuid $xmlname",
SUEXEC_ACTION_CONTINUE);
if ($retval != 0) {
if ($retval < 0) {
$errors["error"] =
"Transient error(3); please try again later.";
}
else {
if (count($suexec_output_array)) {
$line = $suexec_output_array[0];
$errors["error"] = $line;
}
else {
$errors["error"] =
"Transient error(4); please try again later.";
}
}
return null;
}
unlink($xmlname);
$instance = Instance::Lookup($uuid);
if (!$instance) {
$errors["error"] = "Transient error(5); please try again later.";
return null;
}
if (!$creator) {
$creator = GeniUser::Lookup("sa", $instance->creator_uuid());
}
if (!$creator) {
$errors["error"] = "Transient error(6); please try again later.";
return null;
}
return array($instance, $creator);
}
}
?>
......@@ -137,7 +137,7 @@ function SPITFORM($formfields, $newuser, $errors)
if ($errors) {
while (list ($key, $val) = each ($errors)) {
# Skip internal error, we want the html in those errors
# ands we know it is safe.
# and we know it is safe.
if ($key == "error") {
continue;
}
......@@ -536,99 +536,21 @@ if (!$this_user &&
}
}
#
# This is so we can look up the slice after the backend creates it.
# We tell the backend what uuid to use.
#
$quickvm_uuid = NewUUID();
# Admins can change aggregate.
$options = ($aggregate_urn != "" ? " -a '$aggregate_urn'" : "");
#
# Generate a temporary file and write in the XML goo.
# Invoke the backend.
#
$xmlname = tempnam("/tmp", "quickvm");
if (! $xmlname) {
TBERROR("Could not create temporary filename", 0);
$errors["internal"] = "Transient error(1); please try again later.";
}
elseif (! ($fp = fopen($xmlname, "w"))) {
TBERROR("Could not open temp file $xmlname", 0);
$errors["internal"] = "Transient error(2); please try again later.";
}
else {
fwrite($fp, "<quickvm>\n");
foreach ($args as $name => $value) {
fwrite($fp, "<attribute name=\"$name\">");
fwrite($fp, " <value>" . htmlspecialchars($value) . "</value>");
fwrite($fp, "</attribute>\n");
}
fwrite($fp, "</quickvm>\n");
fclose($fp);
chmod($xmlname, 0666);
}
if (count($errors)) {
SPITFORM($formfields, false, $errors);
SPITFOOTER();
return;
}
#
# Invoke the backend. This will create the user and the slice record
# in the SA database, and then fork off in the background. If the
# first part works, we can return to the user and use some nifty ajax
# and javascript to watch for progress. We use a cookie that holds
# the slice uuid so that the JS code can ask about it.
#
# This option is used to tell the backend that it is okay to look
# in the emulab users table.
#
if (isset($_SERVER['REMOTE_ADDR'])) {
putenv("REMOTE_ADDR=" . $_SERVER['REMOTE_ADDR']);
}
$opt = ($this_user ? "-l" : "");
$opt .= ($aggregate_urn != "" ? " -a '$aggregate_urn'" : "");
$retval = SUEXEC("nobody", "nobody",
"webquickvm $opt -u $quickvm_uuid $xmlname",
SUEXEC_ACTION_CONTINUE);
if ($retval != 0) {
if ($retval < 0) {
$errors["error"] = "Transient error(3); please try again later.";
}
else {
if (count($suexec_output_array)) {
$line = $suexec_output_array[0];
$errors["error"] = $line;
}
else {
$errors["error"] = "Transient error(4); please try again later.";
}
}
SPITFORM($formfields, false, $errors);
SPITFOOTER();
return;
}
unlink($xmlname);
list ($instance, $creator) =
Instance::Instantiate($this_user, $options, $args, $errors);
$instance = Instance::Lookup($quickvm_uuid);
if (!$instance) {
$errors["error"] = "Transient error(5); please try again later.";
SPITFORM($formfields, false, $errors);
SPITFOOTER();
return;
}
if ($this_user) {
$creator = $this_user;
}
else {
$creator = GeniUser::Lookup("sa", $instance->creator_uuid());
}
if (! $creator) {
$errors["error"] = "Transient error(6); please try again later.";
SPITFORM($formfields, false, $errors);
SPITFOOTER();
return;
}
#
# Remember the user and auth key so that we can verify.
#
......
......@@ -6,11 +6,13 @@ require(window.APT_OPTIONS.configObject,
'js/lib/text!template/showtopo-modal.html',
'js/lib/text!template/oops-modal.html',
'js/lib/text!template/rspectextview-modal.html',
'js/lib/text!template/guest-instantiate.html',
// jQuery modules
'filestyle','marked','jquery-ui','jquery-grid'],
function (_, sup, filesize, ShowImagingModal,
manageString, waitwaitString,
rendererString, showtopoString, oopsString, rspectextviewString)
rendererString, showtopoString, oopsString, rspectextviewString,
guestInstantiateString)
{
'use strict';
var editing = 0;
......@@ -24,6 +26,7 @@ function (_, sup, filesize, ShowImagingModal,
var showtopoTemplate = _.template(showtopoString);
var rspectextTemplate = _.template(rspectextviewString);
var oopsTemplate = _.template(oopsString);
var guestInstTemplate = _.template(guestInstantiateString);
function initialize()
{
......@@ -69,7 +72,9 @@ function (_, sup, filesize, ShowImagingModal,
$('#rspectext_div').html(rspectext_html);
var oops_html = oopsTemplate({});
$('#oops_div').html(oops_html);
var guest_html = guestInstTemplate({});
$('#guest_div').html(guest_html);
//
// Fix for filestyle problem; not a real class I guess, it
// runs at page load, and so the filestyle'd button in the
......@@ -201,6 +206,12 @@ function (_, sup, filesize, ShowImagingModal,
$('#renderer_modal_div').html(marked(text));
sup.ShowModal("#renderer_modal");
});
// Handler for guest instantiate submit button, which is in
// the modal.
$('#guest_instantiate_submit_button').click(function (event) {
event.preventDefault();
InstantiateAsGuest();
});
/*
* If we were given an rspec, suck the description and instructions
......@@ -501,6 +512,44 @@ function (_, sup, filesize, ShowImagingModal,
sup.maketopmap("#showtopo_nopicker", xml, null);
}
//
// Instantiate a profile as a guest User.
//
function InstantiateAsGuest()
{
var callback = function(json) {
sup.HideModal("#waitwait-modal");
console.info(json.value);
var message;
if (json.code) {
sup.SpitOops("oops", json.value);
return;
}
//
// Need to set the cookies we get back so that we can
// redirect to the status page.
//
document.cookie =
'quickvm_user=' + json.value.quickvm_user +
'; max-age=86400; path=/; secure';
document.cookie =
'quickvm_authkey=' + json.value.quickvm_authkey +
'; max-age=86400; path=/; secure';
var url = "status.php?uuid=" + json.value.quickvm_uuid;
window.location.replace(url);
}
sup.HideModal("#guest_instantiate_modal");
sup.ShowModal("#waitwait-modal");
var xmlthing = sup.CallServerMethod(ajaxurl,
"manage_profile",
"InstantiateAsGuest",
{"uuid" : uuid});
xmlthing.done(callback);
}
//
// Progress Modal
//
......@@ -540,12 +589,14 @@ function (_, sup, filesize, ShowImagingModal,
EnableButton("profile_delete_button");
EnableButton("profile_instantiate_button");
EnableButton("profile_submit_button");
EnableButton("guest_instantiate_button");
}
function DisableButtons()
{
DisableButton("profile_delete_button");
DisableButton("profile_instantiate_button");
DisableButton("profile_submit_button");
DisableButton("guest_instantiate_button");
}
function EnableButton(button)
{
......
......@@ -25,6 +25,7 @@ chdir("..");
include_once("webtask.php");
chdir("apt");
include_once("profile_defs.php");
include_once("instance_defs.php");
#
# Return clone status.
......@@ -79,6 +80,88 @@ function Do_CloneStatus()
SPITAJAX_RESPONSE($blob);
}
#
# Instantiate as Guest user. Simply a convenience, users could do
# this themselves.
#
# Note that this is going to log the user out. Big simplification,
# big headache otherwise.
#
function Do_GuestInstantiate()
{
global $this_user;
global $ajax_args;
$this_idx = $this_user->uid_idx();
if (!isset($ajax_args["uuid"])) {
SPITAJAX_ERROR(1, "Missing profile uuid");
return;
}
$profile = Profile::Lookup($ajax_args["uuid"]);
if (!$profile) {
SPITAJAX_ERROR(1, "Unknown profile uuid");
return;
}
if ($this_idx != $profile->creator_idx() && !ISADMIN()) {
SPITAJAX_ERROR(1, "Not enough permission");
return;
}
#
# Need to form a guest id. Ideally, lets look for a guest user
# with the same email and use that.
#
$geniuser = GeniUser::LookupByEmail($this_user->email());
if ($geniuser) {
$guestid = $geniuser->uid();
$token = $geniuser->auth_token();
}
else {
$guestid = "g" . substr(GENHASH(), 0, 6);
$token = substr(GENHASH(), 0, 16);
}
$args = array();
$args["username"] = $guestid;
$args["email"] = $this_user->email();
$args["profile"] = $profile->uuid();
$args["auth_token"] = $token;
# Grab first internal (encrypted) ssh key and use it.
$query_result =
DBQueryWarn("select pubkey from user_pubkeys ".
"where uid_idx='$this_idx' and internal=0 limit 1");
if (mysql_num_rows($query_result)) {
$row = mysql_fetch_array($query_result);
$args["sshkey"] = $row[0];
}
#
# Need to log the user out.
#
DBQueryFatal("delete from login where uid_idx='$this_idx'");
#
# Invoke the backend.
#
$errors = array();
list ($instance, $creator) =
Instance::Instantiate(NULL, "", $args, $errors);
if (!$instance) {
SPITAJAX_ERROR(1, $errors["error"]);
}
#
# Return the cookies the clients needs to set, so that it can load
# the status page.
#
SPITAJAX_RESPONSE(array("quickvm_user" => $creator->uuid(),
"quickvm_id" => $guestid,
"quickvm_uuid" => $instance->uuid(),
'quickvm_authkey' => $creator->auth_token()));
}
# Local Variables:
# mode:php
# End:
......
......@@ -38,12 +38,14 @@ $routing = array("myprofiles" =>
array("file" => "instantiate.ajax",
"guest" => true,
"methods" => array("GetProfile" =>
"Do_GetProfile")),
"Do_GetProfile")),
"manage_profile" =>
array("file" => "manage_profile.ajax",
"guest" => false,
"methods" => array("CloneStatus" =>
"Do_CloneStatus")),
"Do_CloneStatus",
"InstantiateAsGuest" =>
"Do_GuestInstantiate")),
"status" =>
array("file" => "status.ajax",
"guest" => true,
......
<!-- This is the guest instantiate modal -->
<div id='guest_instantiate_modal' class='modal fade'>
<div class='modal-dialog'>
<div class='modal-content'>
<div class='modal-body'>
<p>To ensure that your profile works for guest users, you should
instantiate your profile as a guest user and confirm its
operation. You may do this by clicking on the confirm button
below. Please be aware that you will be <b>logged out</b> from your
web session so that the test is accurate.
</p>
<br>
<center>
<button type='button' style='margin-right: 20px;'
class='btn btn-primary btn-sm'
data-dismiss='modal' aria-hidden='true'>
Return to Experiment</button>
<button type='button' class='btn btn-success btn-sm'
id='guest_instantiate_submit_button'>
Confirm</button>
</center>
</div>
</div>
</div>
</div>
......@@ -247,6 +247,12 @@
href='instantiate.php?profile=<%= uuid %>'
type='submit' name='create'>Instantiate
</a>
<button class='btn btn-success btn-sm pull-right' disabled
id='guest_instantiate_button'
style='margin-right: 10px;'
data-toggle='modal' data-target='#guest_instantiate_modal'
type='button' name='delete'>Instantiate as Guest
</button>
<button class='btn btn-danger btn-sm pull-left' disabled
id='profile_delete_button'
style='margin-right: 10px;'
......@@ -283,4 +289,5 @@
<div id='imaging_div'></div>
<div id='renderer_div'></div>
<div id='oops_div'></div>
<div id='guest_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