Commit 8ecf0e1d authored by Leigh Stoller's avatar Leigh Stoller Committed by Gary Wong

First working APT code.

parent b1b0b395
#
# Copyright (c) 2000-2012 University of Utah and the Flux Group.
# Copyright (c) 2000-2013 University of Utah and the Flux Group.
#
# {{{EMULAB-LICENSE
#
......@@ -146,6 +146,11 @@ JSFILES += $(wildcard $(SRCDIR)/js/*.js)
BLOBFILES += $(wildcard blob/*.php3)
APTUIFILES = $(wildcard $(SRCDIR)/aptui/*.php)
APTUIFILES += $(wildcard $(SRCDIR)/aptui/*.js)
APTUIFILES += $(wildcard $(SRCDIR)/aptui/*.css)
UIKITFILES = $(wildcard $(SRCDIR)/aptui/uikit/fonts/*)
# need to make it *.gz; with simply "*",
# we end up sucking over "CVS"
DOWNLOADFILES = $(wildcard $(SRCDIR)/downloads/*.gz)
......@@ -202,6 +207,8 @@ ALLUM = $(notdir $(UMFILES))
ALLJS = $(notdir $(JSFILES))
ALLWISTATS = $(notdir $(WIRELESSSTATSFILES))
ALLBLOB = $(notdir $(BLOBFILES))
ALLAPTUI = $(notdir $(APTUIFILES))
ALLUIKITFONTS = $(notdir $(UIKITFILES))
INSTALLFILES = $(addprefix $(INSTALL_SBINDIR)/, htmlinstall) \
$(addprefix $(INSTALL_WWWDIR)/, $(ALLFILES)) \
......@@ -220,13 +227,16 @@ INSTALLFILES = $(addprefix $(INSTALL_SBINDIR)/, htmlinstall) \
$(addprefix $(INSTALL_WWWDIR)/wireless-stats/, $(ALLWISTATS)) \
$(addprefix $(INSTALL_WWWDIR)/autostatus-icons/, $(ALLICONS)) \
$(addprefix $(INSTALL_WWWDIR)/blob/, $(ALLBLOB)) \
$(addprefix $(INSTALL_WWWDIR)/aptui/, $(ALLAPTUI)) \
$(addprefix $(INSTALL_LIBEXECDIR)/, websearch) \
$(addprefix $(INSTALL_SBINDIR)/, htmlinstall) \
$(addprefix $(INSTALL_WWWDIR)/cvsweb/, $(ALLCVSWEB)) \
$(addprefix $(INSTALL_DIR)/opsdir/www/cvsweb/, $(ALLOPSCVSWEB)) \
$(INSTALL_WWWDIR)/wikidocs/wiki/ignore.html \
$(INSTALL_WWWDIR)/doc/LICENSE.txt \
$(addprefix $(INSTALL_ETCDIR)/, swish.conf)
$(INSTALL_WWWDIR)/aptui/uikit/js/uikit.js \
$(INSTALL_WWWDIR)/aptui/uikit/css/uikit.almost-flat.css \
$(addprefix $(INSTALL_WWWDIR)/aptui/uikit/fonts/, $(ALLUIKITFONTS))
install: $(INSTALLFILES)
-mkdir -p $(INSTALL_WWWDIR)/wikidocs/wiki
......
This diff is collapsed.
/* For the footer */
html, body, #bodycontainer { height: 100%; }
body > #bodycontainer { height: auto; min-height: 100%; }
#bodycontent { padding-bottom: 2.5em; }
#footer {
clear: both;
position: relative;
z-index: 10;
height: 2.5em;
margin-top: -2.5em;
}
#footer div {
font-size: 1.0em;
color: #ddd;
padding: 0.5em;
}
#footer #elabpower {
height: 1.0em;
}
This diff is collapsed.
<?php
#
# Copyright (c) 2000-2013 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("osinfo_defs.php");
include_once("geni_defs.php");
chdir("aptui");
include("quickvm_sup.php");
$ajax_request = 0;
#
# Verify page arguments.
#
$reqargs = OptionalPageArguments("uuid", PAGEARG_STRING,
"ajax_request", PAGEARG_BOOLEAN,
"ajax_method", PAGEARG_STRING);
if (!isset($uuid)) {
if ($ajax_request) {
SPITAJAX_ERROR("must provide uuid");
exit();
}
SPITHEADER(1);
echo "<div class='tm-section tm-section-color-white'>
<div class='uk-container uk-container-center uk-text-center'>
<p class='uk-text-large'>
What experiment would you like to look at?
</p>
</div></div>\n";
SPITFOOTER();
return;
}
#
# See if the quickvm exists. If not, redirect back to the create page
#
$quickvm = QuickVM::Lookup($uuid);
if (!$quickvm) {
if ($ajax_request) {
SPITAJAX_ERROR("no such quickvm uuid");
exit();
}
SPITHEADER(1);
echo "<div class='tm-section tm-section-color-white'>
<div class='uk-container uk-container-center uk-text-center'>
<p class='uk-text-large'>
Experiment does not exist. Redirecting to the front page.
</p>
</div></div>\n";
SPITFOOTER();
flush();
sleep(3);
PAGEREPLACE("quickvm.php");
return;
}
$creator = GeniUser::Lookup("sa", $quickvm->creator_uuid());
if (!$creator) {
if ($ajax_request) {
SPITAJAX_ERROR("no such quickvm uuid");
exit();
}
SPITHEADER(1);
echo "<div class='tm-section tm-section-color-white'>
<div class='uk-container uk-container-center uk-text-center'>
<p class='uk-text-large'>
Hmm, there seems to be a problem.
</p>
</div></div>\n";
SPITFOOTER();
TBERROR("No creator for quickvm $uuid", 0);
return;
}
$slice = GeniSlice::Lookup("sa", $quickvm->slice_uuid());
if (!$slice) {
if ($ajax_request) {
SPITAJAX_ERROR("no such quickvm uuid");
exit();
}
SPITHEADER(1);
echo "<div class='tm-section tm-section-color-white'>
<div class='uk-container uk-container-center uk-text-center'>
<p class='uk-text-large'>
Hmm, there seems to be a problem.
</p>
</div></div>\n";
SPITFOOTER();
TBERROR("No slice for quickvm $uuid", 0);
return;
}
#
# Deal with ajax requests.
#
if (isset($ajax_request)) {
if ($ajax_method == "status") {
SPITAJAX_RESPONSE($quickvm->status());
}
elseif ($ajax_method == "terminate") {
SUEXEC("nobody", "nobody", "webquickvm -k $uuid",
SUEXEC_ACTION_IGNORE);
SPITAJAX_RESPONSE("");
}
elseif ($ajax_method == "manifest") {
SPITAJAX_RESPONSE($quickvm->manifest());
}
elseif ($ajax_method == "gettopomap") {
$experiment = Experiment::LookupByUUID($slice->uuid());
if (!$experiment) {
return "";
}
$pid = $experiment->pid();
$eid = $experiment->eid();
SPITAJAX_RESPONSE(GetTopoMap($creator->uid(), $pid, $eid));
}
elseif ($ajax_method == "gateone_authobject") {
SPITAJAX_RESPONSE(GateOneAuthObject($creator->uid()));
}
exit();
}
SPITHEADER(1);
$style = "style='border: none;'";
$slice_urn = $slice->urn();
$slice_expires = gmdate("Y-m-d H:i:s", strtotime($slice->expires())) . " GMT";
$quickvm_status = $quickvm->status();
$sshkey = chunk_split($creator->SSHKey(), 40);
$creator_uid = $creator->uid();
$creator_email = $creator->email();
$quickvm_profile = $quickvm->profile();
$slice_url = "";
$color = "";
$spin = 1;
if ($quickvm_status == "failed") {
$color = "color=red";
$spin = 0;
}
elseif ($quickvm_status == "ready") {
$color = "color=green";
$spin = 0;
}
elseif ($quickvm_status == "created") {
$spinwidth = "33";
}
elseif ($quickvm_status == "provisioned") {
$spinwidth = "66";
}
echo "<div class='uk-panel uk-panel-box uk-panel-header
uk-container-center uk-margin-bottom uk-width-2-3'>\n";
echo "<table class='uk-table uk-table-condensed' $style>\n";
if ($spin) {
echo "<tr>\n";
echo "<td colspan=2 class='uk-width-5-5' $style>\n";
echo "<div id='quickvm_spinner'>\n";
echo " <div id='quickvm_progress'
class='uk-progress uk-progress-striped uk-active'>\n";
echo " <div class='uk-progress-bar'
id='quickvm_progress_bar'
style='width: ${spinwidth}%;'></div>\n";
echo " </div>\n";
echo "</div>\n";
echo "</td>\n";
echo "</tr>\n";
}
echo "<tr>\n";
echo "<td class='uk-width-1-5' $style>URN:</td>\n";
echo "<td class='uk-width-4-5' $style>$slice_urn</td>\n";
echo "</tr>\n";
echo "<tr>\n";
echo "<td class='uk-width-1-5' $style>State:</td>\n";
echo "<td id='quickvm_status'
class='uk-width-4-5' $style>
<font $color>$quickvm_status</font>\n";
echo "</td>\n";
echo "</tr>\n";
echo "<tr>\n";
echo "<td class='uk-width-1-5' $style>Profile:</td>\n";
echo "<td class='uk-width-4-5' $style>$quickvm_profile</td>\n";
echo "</tr>\n";
echo "<tr>\n";
echo "<td class='uk-width-1-5' $style>Expires:</td>\n";
echo "<td class='uk-width-4-5' $style>$slice_expires - Time left:
<span id='quickvm_countdown'></span></td>\n";
echo "</tr>\n";
echo "</table>\n";
echo "<div class='uk-float-right'>\n";
echo " <button class='uk-button uk-button-primary'
id='extend_button' type=button
onclick=\"ShowModal('#extend_modal'); return false;\">
Extend</button>\n";
echo " <button class='uk-button uk-button-danger'
id='terminate_button' type=button
onclick=\"Terminate('$uuid', 'quickvm.php'); return false;\">
Terminate</button>\n";
echo "</div>\n";
echo "</div>\n";
echo "<div id='showtopo_div'>\n";
#echo "<button class='uk-button uk-button-mini uk-align-center'
# id='showtopo_button' type=button
# onclick=\"ShowTopo('$uuid'); return false;\">
# Show Topology</button>\n";
echo "</div>\n";
#
# A modal to tell people how to extend.
#
echo "<!-- This is a modal -->
<div id='extend_modal' class='uk-modal'>
<div class='uk-modal-dialog'>
<a href='' class='uk-modal-close uk-close'></a>
<div class='uk-panel uk-panel-box uk-panel-margin'>
<p>If you want to extend this experiment so that it does
not self-terminate at the time shown, you will need to register
for a full account. Click on the link below to take you to
the registration page.</p><br>
<button class='uk-button uk-button-primary uk-align-center'
onclick=\"RegisterAccount('$creator_uid',
'$creator_email'); return false;\"
type='submit' name='register'>Register</button>
</div>
</div>
</div>\n";
if (0) {
echo "<div class='uk-panel uk-panel-box uk-panel-header
uk-container-center'>\n";
echo " <div id='gateone_container'
style='font-family: monospace'>
<div id='gateone' style='height: 20em; font-family: monospace'>
</div>
</div>\n";
echo "</div>\n";
}
$location = uniqid("loc");
$auth_object = GateOneAuthObject($creator_uid);
echo "<SCRIPT LANGUAGE=JavaScript>
InitQuickVM('$uuid', '$location', '$auth_object');
StartCountdownClock('$slice_expires');
</SCRIPT>\n";
SPITFOOTER();
?>
function ShowModal(which)
{
modal = new $.UIkit.modal.Modal(which);
modal.show();
console.log('Showing modal ' + which);
}
function HideModal(which)
{
$( which ).hide();
console.log('Showing modal ' + which);
}
function CallMethod(method, callback, uuid)
{
return $.ajax({
// the URL for the request
url: "quickvm_status.php",
// the data to send (will be converted to a query string)
data: {
uuid: uuid,
ajax_request: 1,
ajax_method: method,
},
// whether this is a POST or GET request
type: "GET",
// the type of data we expect back
dataType : "json",
});
}
function GetStatus(uuid)
{
var callback = function(json) {
StatusWatchCallBack(uuid, json.value);
setTimeout(function f() { GetStatus(uuid) }, 5000);
}
var $xmlthing = CallMethod("status", null, uuid);
$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, status)
{
// Check to see if the static variable has been initialized
if (typeof StatusWatchCallBack.laststatus == 'undefined') {
// It has not... perform the initilization
StatusWatchCallBack.laststatus = "";
}
console.log(status);
if (status != StatusWatchCallBack.laststatus) {
status_html = status;
if (status == 'provisioned') {
$("#quickvm_progress_bar").width("66%");
}
else if (status == 'ready') {
status_html = "<font color=green>ready</font>";
if ($("#quickvm_progress").length) {
$("#quickvm_progress").removeClass("uk-progress-striped");
$("#quickvm_progress").removeClass("uk-active");
$("#quickvm_progress").addClass("uk-progress-success");
$("#quickvm_progress_bar").width("100%");
}
ShowTopo(uuid);
}
else if (status == 'failed') {
status_html = "<font color=yellow>failed</font>";
if ($("#quickvm_progress").length) {
$("#quickvm_progress").removeClass("uk-progress-striped");
$("#quickvm_progress").removeClass("uk-active");
$("#quickvm_progress").addClass("uk-progress-danger");
$("#quickvm_progress_bar").width("100%");
}
}
$("#quickvm_status").html(status_html);
}
StatusWatchCallBack.laststatus = status;
}
function Terminate(uuid, url)
{
var callback = function(json) {
window.location.replace(url);
}
$("#terminate_button").prop("disabled", true);
var $xmlthing = CallMethod("terminate", null, uuid);
$xmlthing.done(callback);
}
function ShowTopo(uuid)
{
var callback = function(json) {
if (json.value == "") {
return;
}
console.log(json.value);
var html = "<div>" + json.value + "</div>";
$("#showtopo_div").html(html);
}
var $xmlthing = CallMethod("gettopomap", null, uuid);
$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.log(url);
$("#quickvm_sshurl").html(href);
// StartGateOne(url);
}
var $xmlthing = CallMethod("manifest", null, uuid);
$xmlthing.done(callback);
}
//
// Open up a window to the account registration page.
//
function RegisterAccount(uid, email)
{
$('#extend_modal').hide();
var url = "../newproject.php3?uid=" + uid + "&email=" + email + "";
var win = window.open(url, '_blank');
win.focus();
}
var gateone_authobject = null;
var gateone_location = null;
function InitQuickVM(uuid, location, auth_object)
{
gateone_authobject = auth_object;
gateone_location = location;
GetStatus(uuid);
}
function resetForm($form) {
$form.find('input:text, select, textarea').val('');
}
function StartSSH(uuid, sshurl)
{
var current_date = new Date().getTime();
GateOne.location = "loc" + current_date;
var callback = function(json) {
console.log(json.value);
}
var $xmlthing = CallMethod("gateone_authobject", null, uuid);
$xmlthing.done(callback);
}
function StartGateOne(sshurl)
{
GateOne.location = gateone_location;
// Initialize Gate One:
GateOne.init({"url" : 'https://users.emulab.net:1090/gateone',
"autoConnectURL" : sshurl,
"fillContainer" : false,
"showToolbar" : false,
"terminalFont" : 'monospace',
"auth" : gateone_authobject});
}
//
// Found this with a Google search.
//
function StartCountdownClock(when)
{
// set the date we're counting down to
var target_date = new Date(when).getTime();
// variables for time units
var days, hours, minutes, seconds;
// update the tag with id "countdown" every 1 second
setInterval(function () {
// find the amount of "seconds" between now and target
var current_date = new Date().getTime();
var seconds_left = (target_date - current_date) / 1000;
if (seconds_left <= 0) {
$("#terminate_button").prop("disabled", true);
$("#extend_button").prop("disabled", true);
return;
}
// do some time calculations
days = parseInt(seconds_left / 86400);
seconds_left = seconds_left % 86400;
hours = parseInt(seconds_left / 3600);
seconds_left = seconds_left % 3600;
minutes = parseInt(seconds_left / 60);
seconds = parseInt(seconds_left % 60);
if (days < 9)
days = "0" + days;
if (hours < 9)
hours = "0" + hours;
if (minutes < 9)
minutes = "0" + minutes;
if (seconds < 9)
seconds = "0" + seconds;
countdown = days + ":" + hours + ":" + minutes + ":" + seconds;
$("#quickvm_countdown").html(countdown);
}, 1000);
}
<?php
#
# Copyright (c) 2000-2013 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/>.
#
# }}}
#
function SPITHEADER($thinheader = 0)
{
$height = ($thinheader ? 150 : 250);
echo "<html>
<head>
<title>AptLab.io - SSH</title>
<!-- UIKit -->
<link rel='stylesheet' href='uikit/css/uikit.almost-flat.css'>
<link rel='stylesheet' href='quickvm.css'>
<script src='gateone.js'></script>
<script src='quickvm_sup.js'></script>
<script src='/emulab_sup.js'></script>
<script src='https://code.jquery.com/jquery.js'></script>
<script src='uikit/js/uikit.js'></script>
</head>
<body>
<!-- Container for body, needed for sticky footer -->
<div id='bodycontainer'>
<div id='bodycontent'>
<div class='uk-width-100 uk-container-center'
style='background-color: #ff6600'>
<img class='uk-align-center' style='width: ${height}px'
src='aptlogo.png'/>
</div>\n";
}
function SPITFOOTER()
{
echo "</div>
</div>
<!--- Footer -->
<div id='footer' class='uk-width-100' style='background-color: #ff6600;'>
<div class='uk-align-left'>Powered by
<img src='emulab-whiteout.png' id='elabpower'></div>
<div class='uk-align-right'>&copy; 2013 The University of Utah</div>
</div>
</div>
</body></html>\n";
}
#
# Does not return; page exits.
#
function SPITAJAX_RESPONSE($value)
{
$results = array(
'code' => 0,
'value' => $value
);
echo json_encode($results);
exit();
}
function SPITAJAX_ERROR($msg)
{
$results = array(
'code' => 1,
'value' => $msg
);
echo json_encode($results);
exit();
}
function GateOneAuthObject($uid)
{
#
# We need the secret that is shared with ops.
#
$fp = fopen("/usr/testbed/etc/gateone.key", "r");
if (! $fp) {
TBERROR("Error opening /usr/testbed/etc/gateone.key", 0);
return null;
}
list($api_key,$secret) = preg_split('/:/', fread($fp, 128));
fclose($fp);
if (!($secret && $api_key)) {
TBERROR("Could not get kets from gateone.key", 0);
return null;
}
$secret = chop($secret);
$authobj = array(
'api_key' => $api_key,
'upn' => $uid,
'timestamp' => time() . '000',
'signature_method' => 'HMAC-SHA1',
'api_version' => '1.0'
);
$authobj['signature'] = hash_hmac('sha1',
$authobj['api_key'] . $authobj['upn'] .
$authobj['timestamp'], $secret);
$valid_json_auth_object = json_encode($authobj);
return $valid_json_auth_object;
}
#
# This is a little odd; since we are using our local CM to create
# the experiment, we can just ask for the graphic directly.
#
function GetTopoMap($uid, $pid, $eid)
{
global $TBSUEXEC_PATH;
$xmlstuff = "";
if ($fp = popen("$TBSUEXEC_PATH nobody nobody webvistopology ".
"-x -s $uid $pid $eid", "r")) {
while (!feof($fp) && connection_status() == 0) {
$string = fgets($fp);
if ($string) {
$xmlstuff .= $string;
}
}
return $xmlstuff;
}
else {
return "";
}
}
?>
<?php
#
# Copyright (c) 2000-2013 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.