Commit 5c20908b authored by Leigh B Stoller's avatar Leigh B Stoller

New feature on the admin extend page; Add a Terminate button, that sets the

expiration #days in the future, clears the lockdown, sets the lockout (no
free extensions) and sends the text in the box to the user.
parent c328c2d3
......@@ -55,6 +55,7 @@ sub usage()
print("Usage: manage_instance moreinfo instance [-m message] [filename]\n");
print("Usage: manage_instance extendold instance [-f] seconds\n");
print("Usage: manage_instance utilization instance\n");
print("Usage: manage_instance schedterminate instance [-m message] days [filename]\n");
print("Usage: manage_instance idledata instance\n");
print("Usage: manage_instance openstackstats instance\n");
exit(-1);
......@@ -115,6 +116,7 @@ sub UserError($);
sub DoSnapshot();
sub DoConsole();
sub DoTerminate();
sub DoSchedTerminate();
sub DoExtend();
sub DoExtendOld();
sub DoDenyOrMoreInfo($);
......@@ -198,6 +200,9 @@ elsif ($action eq "consoleurl") {
elsif ($action eq "terminate") {
DoTerminate()
}
elsif ($action eq "schedterminate") {
DoSchedTerminate()
}
elsif ($action eq "refresh") {
DoRefresh()
}
......@@ -1572,7 +1577,6 @@ sub ExtendInternal($$$$)
$lockdown = 1
}
# Need to update slice before creating new credential.
# Need to update slice before creating new credential.
if ($slice->IsExpired()) {
$slice->SetExpiration(time() + $seconds);
}
......@@ -3450,6 +3454,177 @@ sub DoIdleData()
exit($errcode);
}
#
# Schedule slice to terminate. This is an admin action. The lockdown bit
# is cleared, and the lockout bit is set (no more free extensions). The
# expiration is set, and we send email.
#
sub DoSchedTerminate()
{
my $errcode = 1;
my $errmsg;
my $days;
my $reason;
my $creator = $instance->GetGeniUser();
my $slice = $instance->GetGeniSlice();
my $name = $instance->name();
my $url = $instance->webURL();
my $clusters = join(",", map { $_->domain() }
$instance->AggregateList());
my $pcount = $instance->physnode_count();
my $expires_time = str2time($slice->expires());
my $created_time = str2time($instance->created());
my $extensions = $instance->Brand()->ExtensionsEmailAddress();
usage()
if (!@ARGV);
$days = shift(@ARGV);
if (@ARGV == 2) {
my $arg = shift(@ARGV);
if ($arg eq "-m") {
$reason = shift(@ARGV);
}
else {
usage();
}
}
elsif (@ARGV == 1) {
my $filename = shift(@ARGV);
if (! -e $filename) {
fatal("$filename does not exist");
}
open(MSG, $filename) or
fatal("Could not open $filename");
$reason = "";
while (<MSG>) {
$reason .= $_;
}
close(MSG);
}
#
# Create the webtask object; the web interface gave us an anonymous
# webtask, so we can use it before lock.
#
if (defined($webtask_id)) {
$webtask = WebTask->Lookup($webtask_id);
fatal("Could not lookup webtask object")
if (!defined($webtask));
# Convenient.
$webtask->AutoStore(1);
}
#
# Lock the slice in case it is doing something else, like taking
# a disk image.
#
if ($slice->Lock()) {
$errcode = GENIRESPONSE_BUSY;
$errmsg ="Experiment is busy, cannot lock it. Try again later.";
if (defined($webtask)) {
$webtask->output($errmsg);
$webtask->Exited($errcode);
}
print STDERR "$errmsg\n";
exit($errcode);
}
if (defined($reason) &&
!TBcheck_dbslot($reason, "default", "fulltext",
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)) {
$errmsg = "Illegal characters in your reason";
$errcode = 1;
goto bad;
}
if (!TBcheck_dbslot($days, "default", "int",
TBDB_CHECKDBSLOT_WARN|TBDB_CHECKDBSLOT_ERROR)) {
$errmsg = "Illegal integer for length";
$errcode = 1;
goto bad;
}
# No free time.
$instance->Update({"extension_adminonly" => 1});
#
# Need to set the new expiration before we clear the lockdown bit,
# else it might get terminated at the cluster. But, if the
# expiration is already beyond the desired termination point,
# leave it alone, all we need to do is set our local expiration,
# the daemon will take care of it. The reason we do this, is cause
# it is unclear if setting the expiration backwards (at the CM) is
# a legal thing to do (although our CM actually permits this).
#
if ($expires_time < time() + ($days * 3600 * 24)) {
my $seconds = (time() + ($days * 3600 * 24)) - $expires_time;
if ($errcode = ExtendInternal($slice, $seconds, 1, \$errmsg)) {
goto bad;
}
}
# Now we can clear this.
if ($instance->admin_lockdown()) {
if (DoLockdownInternal("clear", "all")) {
SENDMAIL($TBOPS,
"Failed to clear lock down on APT Instance",
"Failed to clear lock down $instance\n".
$instance->webURL() . "\n",
$TBOPS);
}
$errmsg = "Failed to clear lockdown";
$errcode = -1;
goto bad;
}
my $expires = POSIX::strftime("20%y-%m-%d %H:%M:%S %Z",
localtime(str2time($slice->expires())));
my $created = POSIX::strftime("20%y-%m-%d %H:%M:%S %Z",
localtime(str2time($instance->created())));
my $message = "The site administrator has scheduled this experiment\n".
"to terminate in $days days.";
my $subject = "Experiment Termination Warning: $name";
#
# New extension mechanism
#
my $extensionargs = {
"action" => "request",
"wanted" => $days,
"granted" => $days,
"admin" => 1,
"uid" => $this_user->uid(),
"uid_idx" => $this_user->uid_idx(),
"message" => $message,
};
if (defined($reason)) {
$extensionargs->{"reason"} = $reason;
}
if (!defined(APT_Instance::ExtensionInfo->Create($instance,
$extensionargs))) {
print STDERR "Could not create extension info object\n";
}
$instance->Brand()->SendEmail($creator->email(), $subject,
$message . "\n\n" .
(defined($reason) ? $reason . "\n\n" : "") .
"Your experiment was started on $created\n".
"Your experiment will now expire at $expires\n".
"You are using $pcount physical nodes.\n".
"It is running on $clusters\n\n".
"$url\n",
"From: $extensions\n" .
"BCC: $extensions");
if (defined($webtask)) {
$webtask->Exited(0);
}
$slice->UnLock();
exit(0);
bad:
print STDERR $errmsg . "\n";
if (defined($webtask)) {
$webtask->output($errmsg);
$webtask->Exited($errcode);
}
exit($errcode);
}
#
# Write instance credentials to files.
#
......
......@@ -27,6 +27,7 @@ function (_, sup, moment, ShowIdleGraphs,
LoadUtilization();
LoadIdleData();
LoadFirstRow();
LoadOpenStack();
// Second row is the user/project usage summarys. We make two calls
// and use jquery "when" to wait for both to finish before running
......@@ -84,6 +85,11 @@ function (_, sup, moment, ShowIdleGraphs,
Action("moreinfo");
return false;
});
$('#do-terminate').click(function (event) {
event.preventDefault();
Action("terminate");
return false;
});
}
//
......@@ -96,7 +102,9 @@ function (_, sup, moment, ShowIdleGraphs,
var method = (action == "extend" ?
"RequestExtension" :
(action == "moreinfo" ?
"MoreInfo" : "DenyExtension"));
"MoreInfo" :
(action == "terminate" ?
"SchedTerminate" : "DenyExtension")));
var callback = function(json) {
sup.HideModal("#waitwait-modal");
......@@ -225,6 +233,29 @@ function (_, sup, moment, ShowIdleGraphs,
"exptID" : "#expt-traffic-panel-div"});
}
//
// Openstacks stats.
//
function LoadOpenStack()
{
var callback = function(json) {
if (json.code) {
return;
}
// Might not be any.
if (!json.value || json.value == "") {
return;
}
var html = "<pre>" + json.value + "</pre>";
$("#openstack-panel-div").removeClass("hidden");
$("#openstack-panel-content").html(html);
};
var xmlthing = sup.CallServerMethod(null, "status", "OpenstackStats",
{"uuid" : window.UUID});
xmlthing.done(callback);
}
// Helper.
function decodejson(id) {
return JSON.parse(_.unescape($(id)[0].textContent));
......
......@@ -134,6 +134,8 @@ $routing = array("myprofiles" =>
"Do_DenyExtension",
"MoreInfo" =>
"Do_MoreInfo",
"SchedTerminate" =>
"Do_SchedTerminate",
"SnapShot" =>
"Do_Snapshot",
"SnapshotStatus" =>
......
......@@ -55,6 +55,10 @@ pre {
class='form-control'
rows=5></textarea>
<div style="margin-top: 10px;">
<button class='btn btn-primary btn-sm'
style='margin-right: 20px;'
id='do-terminate'
type='submit' name='moreinfo'>Terminate</button>
<button class='btn btn-danger btn-sm'
style='margin-right: 20px;'
id='deny-extension'
......@@ -65,7 +69,7 @@ pre {
id='do-extension'
type='submit' name='request'>Extend</button>
<button class='btn btn-primary btn-sm'
style='margin-left: 20px;'
style='margin-left: 30px;'
id='do-moreinfo'
type='submit' name='moreinfo'>More Info</button>
</div>
......@@ -121,6 +125,29 @@ pre {
</div>
</div>
</div>
<div class='row'>
<div class='col-sm-10 col-sm-offset-1
col-xs-12 col-xs-offset-0'>
<div class='panel panel-default hidden' id="openstack-panel-div">
<div class="panel-heading">
<h5>
<a data-toggle="collapse" id="openstack-toggle"
href="#openstack-collapse"><span>Openstack Stats</span>
<span class="glyphicon glyphicon-chevron-right pull-right"></span>
</a>
</h5>
</div>
<div id="openstack-collapse"
class="panel-collapse collapse">
<div class='panel-body'>
<div class="scrollable-panel"
id="openstack-panel-content"
data-status="minimized"></div>
</div>
</div>
</div>
</div>
</div>
<div class='row'>
<div class='col-sm-10 col-sm-offset-1
col-xs-12 col-xs-offset-0'>
......
......@@ -3,6 +3,10 @@
max-height:350px;
height:350px;
}
.smalldiv {
max-height:250px;
height:250px;
}
</style>
<div class='row'>
<div class='col-lg-6 col-lg-offset-3
......
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