Commit 486c2915 authored by Leigh B Stoller's avatar Leigh B Stoller

Several changes:

* Add a "lockdown" checkbox to status page (red-dot) next to the lockout
  checkbox.

* Change Lockdown on adminextend page to the an active checkbox (like
  lockout).

* Add openstackgraphs.js, not in use yet.
parent 3831c899
......@@ -153,6 +153,15 @@ function (_, sup, moment, ShowIdleGraphs,
$('#lockout-checkbox').change(function() {
DoLockout($(this).is(":checked"));
});
// lockdown change event handler.
$('#lockdown-checkbox').change(function() {
DoLockdown($(this).is(":checked"));
});
// This activates the popover subsystem.
$('[data-toggle="popover"]').popover({
trigger: 'hover',
placement: 'auto',
});
}
});
}
......@@ -222,6 +231,27 @@ function (_, sup, moment, ShowIdleGraphs,
xmlthing.done(callback);
}
//
// Request lockdown set/clear.
//
function DoLockdown(lockdown)
{
lockdown = (lockdown ? 1 : 0);
var callback = function(json) {
sup.HideModal("#waitwait-modal");
if (json.code) {
alert("Failed to change lockdown: " + json.value);
return;
}
}
sup.ShowModal("#waitwait-modal");
var xmlthing = sup.CallServerMethod(null, "status", "Lockdown",
{"uuid" : window.UUID,
"lockdown" : lockdown});
xmlthing.done(callback);
}
//
// Slothd graphs.
//
......
//
// Slothd graphs
//
define(['underscore', 'js/quickvm_sup', 'moment'],
function(_, sup, moment)
{
'use strict';
var uuid = null;
var divID = null;
var cpu = [];
var net = [];
function LoadOpenstackData()
{
var callback = function(json) {
var openstackdata = JSON.parse(json.value);
console.info("openstack", openstackdata);
// First get the mapping of VM UUIDs to VM details.
var vmmap = {};
var index = 0;
_.each(openstackdata.info.vms, function(vmlist, hostname) {
_.each(vmlist, function(details, uuid) {
vmmap[uuid] = details;
// And the pnode vname/nodeid
details["hostvname"] =
openstackdata.info.host2vname[hostname];
details["hostpnode"] =
openstackdata.info.host2pnode[hostname];
details["index"] = index;
cpu[index] = {
"type" : "bar",
"yAxis" : 1,
"key" : details.name,
"values" : [],
};
net[index++] = {
"type" : "line",
"yAxis" : 2,
"key" : details.name,
"values" : [],
};
});
});
console.info("vmmap", vmmap);
_.each(openstackdata.periods, function(data, time) {
console.log(time, data);
_.each(data.cpu_util, function(utildata, hostname) {
_.each(utildata.vms, function(util, uuid) {
var index = vmmap[uuid].index;
var i = cpu[index].values.length;
cpu[index].values[i] = {
// convert seconds to milliseconds.
"x" : parseInt(time),
"y" : util,
};
});
});
_.each(data["network.outgoing.bytes.rate"],
function(utildata, hostname) {
_.each(utildata.vms, function(rate, uuid) {
console.info(time, hostname, uuid, rate);
var index = vmmap[uuid].index;
var i = net[index].values.length;
net[index].values[i] = {
// convert seconds to milliseconds.
"x" : parseInt(time),
"y" : rate,
};
});
});
});
console.info("cpu and net", cpu, net);
$(divID).removeClass("hidden");
$(divID).append("<div id='foo' class='smalldiv " +
" with-3d-shadow with-transitions'>"+
" <svg></svg>" +
"</div>");
$(divID).append("<div id='bar' class='smalldiv " +
" with-3d-shadow with-transitions'>"+
" <svg></svg>" +
"</div>");
var chart1 = window.nv.models.multiBarChart();
CreateOneGraph(divID + ' #foo svg', chart1, cpu,
"CPU Utilization");
var chart2 = window.nv.models.multiBarChart();
CreateOneGraph(divID + ' #bar svg', chart2, net,
"Network Bytes Transferred");
};
var xmlthing = sup.CallServerMethod(null, "status",
"OpenstackStats",
{"uuid" : uuid});
xmlthing.done(callback);
}
function CreateOneGraph(id, chart, datums, ylabel)
{
chart.showControls(false);
chart.color(d3.scale.category20().range());
var width = parseInt(d3.select(id).style('width')) - 80;
chart.xAxis
.scale(d3.scale.ordinal()
.rangeRoundBands([0,width], .1)
.domain(datums[0].values.map(function(d) {
return d.x; })));
chart.yAxis
.axisLabel(ylabel)
.tickFormat(d3.format(',.2f'));
d3.select(id)
.datum(datums)
.call(chart);
nv.utils.windowResize(chart.update);
}
return function(args) {
uuid = args.uuid;
divID = args.divID;
LoadOpenstackData();
}
}
);
require(window.APT_OPTIONS.configObject,
['underscore', 'js/quickvm_sup', 'moment',
'marked', 'js/lib/uritemplate', 'js/image', 'js/extend',
'js/idlegraphs',
'js/idlegraphs', 'js/openstackgraphs',
'js/lib/text!template/status.html',
'js/lib/text!template/waitwait-modal.html',
'js/lib/text!template/oops-modal.html',
......@@ -14,7 +14,7 @@ require(window.APT_OPTIONS.configObject,
'js/lib/text!template/linktest-modal.html',
'contextmenu'],
function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
ShowExtendModal, ShowIdleGraphs,
ShowExtendModal, ShowIdleGraphs, ShowOpenstackGraphs,
statusString, waitwaitString, oopsString,
registerString, terminateString,
cloneHelpString, snapshotHelpString, oneonlyString,
......@@ -285,6 +285,10 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
$('#lockout_checkbox').change(function() {
DoLockout($(this).is(":checked"));
});
// lockdown change event handler.
$('#lockdown_checkbox').change(function() {
DoLockdown($(this).is(":checked"));
});
// Quarantine change event handler.
$('#quarantine_checkbox').change(function() {
DoQuarantine($(this).is(":checked"));
......@@ -384,8 +388,6 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
// Call back for above.
function StatusWatchCallBack(json)
{
console.info(json);
if (json.code) {
// GENIRESPONSE_SEARCHFAILED
if (json.code == 12) {
......@@ -401,6 +403,8 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
var status_html = "";
if (instanceStatus != lastStatus) {
console.info(json);
status_html = status;
var bgtype = "panel-info";
......@@ -762,6 +766,27 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
xmlthing.done(callback);
}
//
// Request lockdown set/clear.
//
function DoLockdown(lockdown)
{
lockdown = (lockdown ? 1 : 0);
var callback = function(json) {
sup.HideModal("#waitwait-modal");
if (json.code) {
alert("Failed to change lockdown: " + json.value);
return;
}
}
sup.ShowModal("#waitwait-modal");
var xmlthing = sup.CallServerMethod(ajaxurl, "status", "Lockdown",
{"uuid" : uuid,
"lockdown" : lockdown});
xmlthing.done(callback);
}
//
// Request panic mode set/clear.
//
......@@ -2489,22 +2514,20 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
//
function CreateOpenstackTab()
{
var tabname = "Openstack";
// Not updating the content yet, so just return if we have it.
if ($("#" + tabname).length) {
if ($("#Openstack").length) {
return;
}
var callback = function(json) {
console.log(json);
if (! $("#" + tabname).length) {
if (! $("#Openstack").length) {
// The tab.
var html = "<li><a href='#" + tabname + "' data-toggle='tab'>" +
tabname + "" +
var html = "<li><a href='#Openstack' " +
"id='show_Openstack_tab' data-toggle='tab'>" +
"Openstack Data" +
"<button class='close' type='button' " +
" id='" + tabname + "_kill'>x</button>" +
" id='Openstack_kill'>x</button>" +
"</a>" +
"</li>";
......@@ -2512,32 +2535,50 @@ function (_, sup, moment, marked, UriTemplate, ShowImagingModal,
$("#quicktabs_ul").append(html);
// Install a click handler for the X button.
$("#" + tabname + "_kill").click(function(e) {
$("#Openstack_kill").click(function(e) {
e.preventDefault();
// remove the li from the ul.
$(this).parent().parent().remove();
// Remove the content div.
$("#" + tabname).remove();
$("#Openstack").remove();
// Activate the "profile" tab.
$('#quicktabs_ul a[href="#profile"]').tab('show');
});
// The content div.
html = "<div class='tab-pane' id='" + tabname + "'></div>";
html = "<div class='tab-pane' id='Openstack'></div>";
// Add the tab content wrapper to the DOM,
$("#quicktabs_content").append(html);
}
else {
// Switch back to it.
$('#quicktabs_ul a[href="#' + tabname + '"]').tab('show');
$('#quicktabs_ul a[href="#Openstack"]').tab('show');
}
//
// Inside tab content is just a big string.
//
var html = "<div style='overflow-y: scroll;'><pre>" +
json.value + "</pre></div>";
$('#' + tabname).html(html);
var html =
"<div> " +
" <div id='Openstack_chart_div' class='hidden'></div>" +
" <pre>" + json.value + "</pre></div>";
$('#Openstack').html(html);
/*
* We cannot draw the graphs until the tab is actually visible,
* D3 cannot handle drawing if there is no actual space allocated.
* So lets just wait till the user clicks on the tab.
*/
var handler = function () {
$('#show_Openstack_tab').off("shown.bs.tab", handler);
ShowOpenstackGraphs({"uuid" : uuid,
"divID" : '#Openstack_chart_div'});
};
if (0) {
$('#show_Openstack_tab').on("shown.bs.tab", handler);
}
};
var xmlthing = sup.CallServerMethod(null, "status", "OpenstackStats",
{"uuid" : uuid});
......
......@@ -150,6 +150,8 @@ $routing = array("myprofiles" =>
"Do_DecryptBlocks",
"Lockout" =>
"Do_Lockout",
"Lockdown" =>
"Do_Lockdown",
"Quarantine" =>
"Do_Quarantine",
"LinktestControl" =>
......
......@@ -413,7 +413,7 @@ function Do_DenyOrMoreinfo($action)
{
global $instance, $creator, $this_user, $suexec_output;
global $ajax_args;
$action = ($action == "deny" ? "denyextension" : "moreinfo");
$extrargs = "";
if (StatusSetupAjax(1)) {
goto bad;
......@@ -439,11 +439,25 @@ function Do_DenyOrMoreinfo($action)
$fp = fopen($filename, "w");
fwrite($fp, $reason);
fclose($fp);
}
}
if ($action == "terminate") {
if (!isset($ajax_args["howlong"]) || $ajax_args["howlong"] == "") {
SPITAJAX_ERROR(1, "Missing number of days");
goto bad;
}
$days = $ajax_args["howlong"];
if (! preg_match("/^\d+$/", $days)) {
SPITAJAX_ERROR(1, "Invalid characters in days");
goto bad;
}
$extrargs = $days;
}
$action = ($action == "deny" ? "denyextension" :
($action == "terminate" ? "schedterminate": "moreinfo"));
$webtask = WebTask::CreateAnonymous();
$retval = SUEXEC("nobody", "nobody",
"webmanage_instance -t " . $webtask->task_id() . " -- ".
" $action $uuid " .
" $action $uuid $extrargs " .
(isset($filename) ? $filename : ""),
SUEXEC_ACTION_IGNORE);
$webtask->Refresh();
......@@ -487,6 +501,10 @@ function Do_MoreInfo()
{
Do_DenyOrMoreinfo("info");
}
function Do_SchedTerminate()
{
Do_DenyOrMoreinfo("terminate");
}
#
# Request automatic extension.
......@@ -1332,6 +1350,73 @@ function Do_Lockout()
SPITAJAX_RESPONSE("Success");
}
#
# Set or clear the lockdown flag
#
function Do_Lockdown()
{
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 profile uuid");
return;
}
if (!isset($ajax_args["lockdown"])) {
SPITAJAX_ERROR(1, "Missing lockdown value");
return;
}
$uuid = $ajax_args["uuid"];
$instance = Instance::Lookup($uuid);
if (!$instance) {
SPITAJAX_ERROR(1, "Unknown instance uuid");
return;
}
$action = ($ajax_args["lockdown"] ? "set" : "clear");
#
# Call out to the backend.
#
$webtask_id = WebTask::GenerateID();
$retval = SUEXEC("nobody", "nobody",
"webmanage_instance -t $webtask_id -- ".
" lockdown $uuid $action admin ",
SUEXEC_ACTION_IGNORE);
$webtask = WebTask::Lookup($webtask_id);
if ($retval != 0) {
if ($retval < 0) {
SPITAJAX_ERROR(-11, "Internal error, cannot proceed.");
# Notify tbops.
SUEXECERROR(SUEXEC_ACTION_CONTINUE);
}
elseif ($webtask) {
SPITAJAX_ERROR(1, $webtask->TaskValue("output"));
}
elseif ($suexec_output != "") {
SPITAJAX_ERROR(1, $suexec_output);
}
else {
SUEXECERROR(SUEXEC_ACTION_CONTINUE);
SPITAJAX_ERROR(-1, "Internal Error. Please try again later");
}
if ($webtask) {
$webtask->Delete();
}
return;
}
if ($webtask) {
$webtask->Delete();
}
SPITAJAX_RESPONSE("Success");
}
#
# Handle Quarantine request/clear.
#
......
......@@ -293,13 +293,26 @@ pre {
<td class="format-date"><%- expinfo.expires %></td>
</tr>
<tr>
<td>Lockout:</td>
<td>
<span data-toggle='popover'
data-delay='{"hide":1000, "show":500}'
data-content="When checked, only administrator can extend
this experiment. No free time is granted to
user at all.">Lockout:</span></td>
<td><input type="checkbox" id="lockout-checkbox"
<% if (expinfo.lockout) { %>checked<% } %> >
</td>
<td>Lockdown:</td>
<td><% if (expinfo.lockdown) { %>
<span class="text-danger">Yes</span><% } else { %>No<% } %></td>
<td>
<span data-toggle='popover'
data-delay='{"hide":1000, "show":500}'
data-content="When checked, the experiment
cannot be terminated until the lockdown bit
is cleared by an admininstrator, or if the
user verifies
the lockdown code when clicking the Terminate
button.">Lockdown:</span></td>
<td><input type="checkbox" id="lockdown-checkbox"
<% if (expinfo.lockdown) { %>checked<% } %> >
</td>
</tbody>
</table>
......
......@@ -95,9 +95,6 @@
<%- sliceExpires %></span>
(<span id='quickvm_countdown'></span>)
</span>
<% if (isadmin && lockdown) { %>
<span class='text-danger'><small>locked down</small></span>
<% } %>
</td>
</tr>
</table>
......@@ -138,6 +135,19 @@
<input type="checkbox" id="lockout_checkbox"
<% if (lockout) { %>checked<% } %> >Lockout</label>
</div>
<div class='pull-left'
data-toggle='popover'
data-delay='{"hide":1000, "show":500}'
data-content="When checked, the experiment
cannot be terminated until the lockdown bit
is cleared by an admininstrator, or if the user
verifies
the lockdown code when clicking the Terminate
button.">
<label class="checkbox-inline" style='margin-right: 10px;'>
<input type="checkbox" id="lockdown_checkbox"
<% if (lockdown) { %>checked<% } %> >Lockdown</label>
</div>
<div class='pull-left'
data-toggle='popover'
data-delay='{"hide":1000, "show":500}'
......
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