Commit fc0ee218 authored by Leigh Stoller's avatar Leigh Stoller

Redo all the extension support in manage_instance, not sure why I did all

that in PHP, yuck. This is mostly to get ready for beefing up the extension
code as discussed, and do not want to do any of it in PHP.

Note; in another commit I added emulabfeature support to PHP (via a callout
to the perl code), I am going to roll this out slowly. Well, admins will
get it right away.
parent 857d5f3d
......@@ -52,6 +52,7 @@ use emdb;
use libtestbed;
use Brand;
use APT_Profile;
use APT_Aggregate;
use APT_Geni;
use Genixmlrpc;
use GeniResponse;
......@@ -954,6 +955,62 @@ sub UpdateImageStatus($$)
return 0;
}
sub AddExtensionHistory($$)
{
my ($self, $reason) = @_;
my $uuid = $self->uuid();
my $safe_text = DBQuoteSpecial($reason);
return DBQueryWarn("update apt_instances set ".
" extension_history=CONCAT($safe_text,".
" IFNULL(extension_history,'')) ".
"where uuid='$uuid'");
}
sub ExtensionRequested($$$)
{
my ($self, $reason, $granted) = @_;
my $uuid = $self->uuid();
my $safe_text = DBQuoteSpecial($reason);
return DBQueryWarn("update apt_instances set ".
" extension_reason=$safe_text,".
" extension_requested=1, ".
" extension_count=extension_count+1, ".
" extension_days=extension_days+${granted} ".
"where uuid='$uuid'");
}
sub BumpExtensionCount($$)
{
my ($self, $granted) = @_;
my $uuid = $self->uuid();
return DBQueryWarn("update apt_instances set ".
" extension_count=extension_count+1, ".
" extension_days=extension_days+${granted} ".
"where uuid='$uuid'");
}
#
# Return the list APT_Aggregate objects for an instance.
#
sub AptAggregateList($)
{
my ($self) = @_;
my @results = ();
foreach my $agg ($self->AggregateList()) {
my $aptagg = APT_Aggregate->Lookup($agg->aggregate_urn());
if (!defined($aptagg)) {
print STDERR "Could not get APT_Aggregate object for $agg\n";
return ();
}
push(@results, $aptagg);
}
return @results;
}
###################################################################
package APT_Instance::Aggregate;
use emdb;
......@@ -1824,7 +1881,7 @@ sub CreateImage($$$$;$$$)
my ($self, $sliver_urn, $imagename, $update_prepare,
$copyback_uuid, $bsname) = @_;
my $authority = $self->GetGeniAuthority();
my$geniuser = $self->instance()->GetGeniUser();
my $geniuser = $self->instance()->GetGeniUser();
my $slice = $self->instance()->GetGeniSlice();
my $context = APT_Geni::GeniContext();
return undef
......
This diff is collapsed.
......@@ -305,6 +305,10 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
if (window.APT_OPTIONS.oneonly) {
sup.ShowModal('#oneonly-modal');
}
if (window.APT_OPTIONS.thisUid == window.APT_OPTIONS.creatorUid &&
window.APT_OPTIONS.extension_denied) {
ShowExtensionDeniedModal();
}
else if (window.APT_OPTIONS.snapping) {
ShowProgressModal();
}
......@@ -1016,8 +1020,8 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
var callback = function(json) {
console.info(json);
sup.HideModal('#waitwait-modal');
sup.HideWaitWait();
if (json.code) {
sup.SpitOops("oops", "Failed to delete nodes");
$('#error_panel_text').text(json.value);
......@@ -1028,7 +1032,8 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
// Trigger status to change the nodes.
GetStatus();
}
sup.ShowModal('#waitwait-modal');
sup.ShowWaitWait("This will take 30-60 seconds. " +
"Patience please.");
var xmlthing = sup.CallServerMethod(ajaxurl,
"status",
"DeleteNodes",
......@@ -2404,6 +2409,20 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
}
}
}
function ShowExtensionDeniedModal()
{
if ($('#extension_denied_reason').length) {
$("#extension-denied-modal-reason")
.text($('#extension_denied_reason').text());
}
$('#extension-denied-modal-dismiss').click(function () {
sup.HideModal("#extension-denied-modal");
sup.CallServerMethod(null, "status", "dismissExtensionDenied",
{"uuid" : uuid});
});
sup.ShowModal("#extension-denied-modal");
}
$(document).ready(initialize);
});
......@@ -295,10 +295,192 @@ function Do_GetSSHAuthObject()
SPITAJAX_RESPONSE($auth);
}
function Do_RequestExtension()
{
global $instance, $creator, $this_user, $suexec_output;
global $ajax_args;
$autoextend_maximum = TBGetSiteVar("aptui/autoextend_maximum");
if (StatusSetupAjax(1)) {
goto bad;
}
if (isset($this_user)) {
$project = Project::Lookup($instance->pid_idx());
if ($project) {
$group = $project->DefaultGroup();
if (ISADMINISTRATOR() ||
!FeatureEnabled("NewPortalExtend", $this_user, $group)) {
TBERROR("Using old extension code", 0);
return Do_RequestExtensionOld();
}
}
}
$uuid = $instance->uuid();
$slice = GeniSlice::Lookup("sa", $instance->slice_uuid());
if (!slice) {
SPITAJAX_ERROR(1, "no slice for instance");
goto bad;
}
if ($autoextend_maximum == 0 && !ISADMIN()) {
SPITAJAX_ERROR(1, "Extensions are currenly disabled; please ".
"contact us if you need to make special arrangements.");
goto bad;
}
if (!isset($ajax_args["howlong"]) || $ajax_args["howlong"] == "") {
SPITAJAX_ERROR(1, "Missing number of days");
goto bad;
}
$wanted = $ajax_args["howlong"];
if (! preg_match("/^\d+$/", $wanted)) {
SPITAJAX_ERROR(1, "Invalid characters in days");
goto bad;
}
if (ISADMIN()) {
if ($wanted < 1 || $wanted > 365) {
SPITAJAX_ERROR(1, "Must be an integer 1 <= days <= 365");
goto bad;
}
if (isset($ajax_args["reason"]) && $ajax_args["reason"] != "") {
$reason = $ajax_args["reason"];
}
}
else {
if (!isset($ajax_args["reason"]) || $ajax_args["reason"] == "") {
SPITAJAX_ERROR(1, "Missing reason");
goto bad;
}
$reason = $ajax_args["reason"];
}
if (isset($reason)) {
if (!TBvalid_fulltext($reason)) {
SPITAJAX_ERROR(1, "Illegal characters in reason");
goto bad;
}
$filename = tempnam("/tmp", "extension");
$fp = fopen($filename, "w");
fwrite($fp, $reason);
fclose($fp);
}
$webtask = WebTask::CreateAnonymous();
$retval = SUEXEC("nobody", "nobody",
"webmanage_instance -t " . $webtask->task_id() . " -- ".
" extend $uuid $wanted ".
(isset($filename) ? $filename : ""),
SUEXEC_ACTION_IGNORE);
$webtask->Refresh();
if (isset($filename)) {
unlink($filename);
}
SUEXECERROR(SUEXEC_ACTION_CONTINUE);
if ($retval != 0) {
if ($webtask->exited()) {
SPITAJAX_ERROR($webtask->exitcode(), $webtask->TaskValue("output"));
#
# This is an important error, tell tbops.
#
if ($webtask->exitcode() == GENIRESPONSE_REFUSED) {
SUEXECERROR(SUEXEC_ACTION_CONTINUE);
}
}
elseif ($retval < 0) {
SPITAJAX_ERROR($retval, "Internal error, cannot proceed.");
# Notify tbops.
SUEXECERROR(SUEXEC_ACTION_CONTINUE);
}
else {
SPITAJAX_ERROR($retval, $suexec_output);
}
$webtask->Delete();
goto bad;
}
# Refresh.
$slice = GeniSlice::Lookup("sa", $instance->slice_uuid());
$new_expires = date("Y-m-d H:i:s T", strtotime($slice->expires()));
$webtask->Delete();
SPITAJAX_RESPONSE($new_expires);
bad:
delay:
sleep(1);
}
function Do_DenyExtension()
{
global $instance, $creator, $this_user, $suexec_output;
global $ajax_args;
if (StatusSetupAjax(1)) {
goto bad;
}
$uuid = $instance->uuid();
$slice = GeniSlice::Lookup("sa", $instance->slice_uuid());
if (!slice) {
SPITAJAX_ERROR(1, "no slice for instance");
goto bad;
}
if (!ISADMIN()) {
SPITAJAX_ERROR(1, "You do not have permission to do this.");
goto bad;
}
if (isset($ajax_args["message"]) && $ajax_args["message"] != "") {
$message = $ajax_args["message"];
if (!TBvalid_fulltext($message)) {
SPITAJAX_ERROR(1, "Illegal characters in message");
goto bad;
}
$filename = tempnam("/tmp", "extension");
$fp = fopen($filename, "w");
fwrite($fp, $message);
fclose($fp);
}
$webtask = WebTask::CreateAnonymous();
$retval = SUEXEC("nobody", "nobody",
"webmanage_instance -t " . $webtask->task_id() . " -- ".
" denyextension $uuid " .
(isset($filename) ? $filename : ""),
SUEXEC_ACTION_IGNORE);
$webtask->Refresh();
if (isset($filename)) {
unlink($filename);
}
SUEXECERROR(SUEXEC_ACTION_CONTINUE);
if ($retval != 0) {
if ($webtask->exited()) {
SPITAJAX_ERROR($webtask->exitcode(), $webtask->TaskValue("output"));
#
# This is an important error, tell tbops.
#
if ($webtask->exitcode() == GENIRESPONSE_REFUSED) {
SUEXECERROR(SUEXEC_ACTION_CONTINUE);
}
}
elseif ($retval < 0) {
SPITAJAX_ERROR($retval, "Internal error, cannot proceed.");
# Notify tbops.
SUEXECERROR(SUEXEC_ACTION_CONTINUE);
}
else {
SPITAJAX_ERROR($retval, $suexec_output);
}
$webtask->Delete();
goto bad;
}
$webtask->Delete();
SPITAJAX_RESPONSE("Success");
bad:
$webtask->Delete();
sleep(1);
}
#
# Request automatic extension.
#
function Do_RequestExtension()
function Do_RequestExtensionOld()
{
global $instance, $creator, $this_user, $suexec_output;
global $ajax_args;
......@@ -310,9 +492,6 @@ function Do_RequestExtension()
$needapproval = 0;
$granted = 0;
if (StatusSetupAjax(1)) {
goto bad;
}
$uuid = $instance->uuid();
$slice = GeniSlice::Lookup("sa", $instance->slice_uuid());
if (!slice) {
......@@ -466,7 +645,7 @@ function Do_RequestExtension()
if ($granted > 0) {
$seconds = 3600 * 24 * $granted;
$retval = SUEXEC("nobody", "nobody",
"webmanage_instance extend $uuid $seconds",
"webmanage_instance extendold $uuid $seconds",
SUEXEC_ACTION_IGNORE);
}
......@@ -547,72 +726,6 @@ delay:
sleep(1);
}
#
# Deny extension,
#
function Do_DenyExtension()
{
global $instance, $creator, $this_user, $suexec_output;
global $ajax_args;
global $TBMAIL_OPS, $APTMAIL, $EXTENSIONS, $APTBASE;
$reason = "";
$message = "";
if (StatusSetupAjax(1)) {
goto bad;
}
$uuid = $instance->uuid();
$slice = GeniSlice::Lookup("sa", $instance->slice_uuid());
if (!slice) {
SPITAJAX_ERROR(1, "no slice for instance");
goto bad;
}
$instance_name = $instance->name();
# Until old instances are gone.
if (!$instance_name) {
list ($a,$b,$instance_name) = Instance::ParseURN($slice->urn());
}
if (!ISADMIN()) {
SPITAJAX_ERROR(1, "You do not have permission to do this.");
goto bad;
}
$reason = "Your extension was denied by the site administrator!\n";
if (isset($ajax_args["message"]) && $ajax_args["message"] != "") {
$reason .= "\n" . $ajax_args["message"];
}
$expires = date("Y-m-d H:i:s T", strtotime($slice->expires()));
$created = date("Y-m-d H:i:s T", strtotime($instance->created()));
$now = date("Y-m-d H:i:s T", time());
#
# We store each extension request in an ongoing text field.
#
$text =
"Date: $now\n".
"Expires: $expires\n".
"Reason:\n".
$reason . "\n\n".
"-----------------------------------------------\n";
$instance->AddExtensionHistory($text);
$instance->SendEmail($creator->email(),
"Experiment Extension Denied: $instance_name",
$reason .
"\n\n".
"Your experiment was started on $created\n".
"Your experiment expires at $expires\n".
"$APTBASE/status.php?uuid=$uuid\n",
"From: $EXTENSIONS\n" .
"BCC: $EXTENSIONS");
$instance->SetExtensionRequested(0);
SPITAJAX_RESPONSE("Success");
bad:
delay:
sleep(1);
}
#
# Helper for above.
#
......@@ -1385,6 +1498,38 @@ function Do_Linktest()
}
}
#
# Clea the extension denied flag; user has seen it and dismissed it.
#
function Do_DismissExtensionDenied()
{
global $this_user;
global $ajax_args;
if (!isset($this_user) || !ISADMIN()) {
SPITAJAX_ERROR(1, "Not enough permission.");
return;
}
$this_idx = $this_user->uid_idx();
if (!isset($ajax_args["uuid"])) {
SPITAJAX_ERROR(1, "Missing instance uuid");
return;
}
$uuid = $ajax_args["uuid"];
$instance = Instance::Lookup($uuid);
if (!$instance) {
SPITAJAX_ERROR(1, "Unknown instance uuid");
return;
}
if (!DBQueryWarn("update apt_instances set extension_denied='0' ".
"where uuid='$uuid'")) {
SPITAJAX_ERROR(1, "Database failure.");
return;
}
SPITAJAX_RESPONSE("Success");
}
# Local Variables:
# mode:php
# End:
......
......@@ -177,6 +177,9 @@ $extension_reason= ($instance->extension_reason() ?
CleanString($instance->extension_reason()) : "");
$extension_history= ($instance->extension_history() ?
CleanString($instance->extension_history()) : "");
$extension_denied_reason= ($instance->extension_denied_reason() ?
CleanString($instance->extension_denied_reason()) : "");
$extension_denied= $instance->extension_denied();
$freenodes_url = Aggregate::Lookup($instance->aggregate_urn())->FreeNodesURL();
$lockout = $instance->extension_lockout();
$paniced = $instance->paniced();
......@@ -248,6 +251,7 @@ echo " window.APT_OPTIONS.paniced = $paniced;\n";
echo " window.APT_OPTIONS.project = '$project';\n";
echo " window.APT_OPTIONS.extension_requested = " .
$instance->extension_requested() . ";\n";
echo " window.APT_OPTIONS.extension_denied = $extension_denied;\n";
echo " window.APT_OPTIONS.AJAXURL = 'server-ajax.php';\n";
echo " window.APT_OPTIONS.physnode_count = " .
$instance->physnode_count() . ";\n";
......@@ -273,9 +277,12 @@ echo "<link rel='stylesheet'
echo "<link rel='stylesheet' href='css/progress.css'>\n";
echo "<link rel='stylesheet' href='css/codemirror.css'>\n";
echo "<div class='hidden'><textarea id='extension_reason'>$extension_reason</textarea></div>\n";
if ($extension_reason != "") {
if ($extension_history != "") {
echo "<pre class='hidden' id='extension_history'>$extension_history</pre>\n";
}
if ($extension_denied_reason != "") {
echo "<pre class='hidden' id='extension_denied_reason'>$extension_denied_reason</pre>\n";
}
SPITFOOTER();
?>
......@@ -496,6 +496,32 @@
</div>
</div>
</div>
<div id='extension-denied-modal' class='modal fade'>
<div class='modal-dialog'>
<div class='modal-content'>
<div class='modal-header'>
<center><h3>Your recent extension request was denied!</h3></center>
</div>
<div class='modal-body'>
<div class="well" id="extension-denied-modal-reason"></div>
<p>
We sent you an email notification, but just in case you
did not receive it, we are letting you know again.
Clicking Dismiss will hide this message. You may also request
another extension if you have more information to add, or to plead
your case.
</p>
<div>
<center>
<button class='btn btn-primary btn-sm'
id='extension-denied-modal-dismiss'>
Dismiss</button>
</center>
</div>
</div>
</div>
</div>
</div>
<div id='waitwait_div'></div>
<div id='terminate_div'></div>
<div id='oops_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