mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
The page showed controls the backend then refused: power to global viewers, the console, virt-viewer and VDI controls and the root password and SSH key forms to viewers, resize to staff, per-vCPU hotplug, video model and guest agent to non-superusers, clone and options by the clone permission alone, snapshots without change permission. The page now asks the views' own rules (owner, is_change, clone and snapshot permissions, the template rules). OS info, opened from the header, is there for every viewer; the XML editor and tab restoring after a redirect no longer throw when a pane is absent; Settings opens on the first section the user has. The authorization matrix also covers a template VM, the template clone rule and the template snapshot rule.
728 lines
29 KiB
HTML
728 lines
29 KiB
HTML
{% extends "base.html" %}
|
|
{% load static %}
|
|
{% load vm_states %}
|
|
{% load i18n %}
|
|
{% load bootstrap_icons %}
|
|
|
|
{% block title %}{% trans "Instance" %} - {{ instance.name }}{% endblock %}
|
|
|
|
{% block page_heading %}
|
|
{{ instance.name }}{% if instance.title %} ({{ instance.title }}){% endif %}
|
|
{% endblock page_heading %}
|
|
|
|
{% block content %}
|
|
{% include 'pleasewaitdialog.html' %}
|
|
<div>
|
|
<div>
|
|
{% vm_state instance.status as state %}
|
|
<span class="badge bg-{{ state.1 }}">{{ state.0 }}</span>
|
|
|
|
|
<span
|
|
{%if instance.guest_agent %}
|
|
{% if instance.guest_agent_ready %}
|
|
class="badge bg-success"
|
|
title="{% trans "Guest Agent Enabled & Connected" %}"
|
|
{% else %}
|
|
class="badge bg-warning"
|
|
title="{% trans "Guest Agent Enabled but not Connected" %}"
|
|
{% endif %}
|
|
{% else %}
|
|
class="badge bg-danger"
|
|
title="{% trans "Guest Agent Not Enabled & Not Connected" %}"
|
|
{% endif %}>{% bs_icon 'broadcast' size='1em' %}
|
|
</span>
|
|
|
|
|
{% if instance.snapshots %}
|
|
{% bs_icon 'camera'%} <i title="There are {{ instance.snapshots|length }} snapshot(s)"></i>
|
|
|
|
|
{% endif %}
|
|
{% if instance.cur_vcpu %}
|
|
{{ instance.cur_vcpu }} {% trans "VCPU" %}
|
|
{% else %}
|
|
{{ instance.vcpu }} {% trans "VCPU" %}
|
|
{% endif %}
|
|
|
|
|
{{ instance.cur_memory }} {% trans "MB" %} {% trans "RAM" %}
|
|
|
|
|
{% for disk in instance.disks %}
|
|
{{ disk.size|filesizeformat }} {% trans "Disk" %} |
|
|
{% endfor %}
|
|
{% for net in instance.networks %}
|
|
{% for ipv4 in net.ipv4 %}
|
|
{{ ipv4 }} |
|
|
{% endfor %}
|
|
{% endfor %}
|
|
{% if instance.guest_agent_ready %}
|
|
<a class="link-warning" title="{% trans 'Show Instance OS details' %}" onclick="get_osinfo();">
|
|
<span>{% bs_icon 'info-circle' %} </span>
|
|
</a>
|
|
{% endif %}
|
|
<a class="link-success" href="{% url 'instances:instance' instance.id %}" title="{% trans 'Refresh instance info' %}">
|
|
<span>{% bs_icon 'repeat'%} </span>
|
|
</a>
|
|
</div>
|
|
<hr>
|
|
</div>
|
|
|
|
<div id="mainTabMenu">
|
|
<!-- Nav tabs -->
|
|
<ul class="nav nav-pills nav-fill" id="navbtn" role="tablist" aria-label="Instance actions">
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link action-button active" id="power-tab" aria-controls="power" data-bs-toggle="pill" data-bs-target="#power" type="button" role="tab" aria-selected="true">
|
|
<span id="action-block" aria-hidden="true">{% bs_icon 'power' size='2em'%} </span>
|
|
{% trans "Power" %}
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link action-button" id="access-tab" aria-controls="access" data-bs-toggle="pill" data-bs-target="#access" type="button" role="tab" aria-selected="false">
|
|
<span id="action-block" aria-hidden="true">{% bs_icon 'lock' size='2em'%} </span>
|
|
{% trans "Access" %}
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link action-button" id="resize-tab" aria-controls="resize" data-bs-toggle="pill" data-bs-target="#resize" type="button" role="tab" aria-selected="false">
|
|
<span id="action-block" aria-hidden="true">{% bs_icon 'arrows-angle-expand' size='2em'%} </span>
|
|
{% trans "Resize" %}
|
|
</button>
|
|
</li>
|
|
{% if can_snapshot %}
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link action-button" id="snapshots-tab" aria-controls="snapshots" data-bs-toggle="pill" data-bs-target="#snapshots" type="button" role="tab" aria-selected="false">
|
|
<span id="action-block" aria-hidden="true">{% bs_icon 'camera' size='2em'%} </span>
|
|
{% trans "Snapshot" %}
|
|
</button>
|
|
</li>
|
|
{% endif %}
|
|
{% if show_settings %}
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link action-button" id="settings-tab" aria-controls="settings" data-bs-toggle="pill" data-bs-target="#settings" type="button" role="tab" aria-selected="false">
|
|
<span id="action-block" aria-hidden="true">{% bs_icon 'gear-wide-connected' size='2em'%} </span>
|
|
{% trans "Settings" %}
|
|
</button>
|
|
</li>
|
|
{% endif %}
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link action-button" id="graphics-tab" aria-controls="graphics" data-bs-toggle="pill" data-bs-target="#graphics" type="button" role="tab" aria-selected="false">
|
|
<span id="action-block" aria-hidden="true">{% bs_icon 'bar-chart-line' size='2em'%} </span>
|
|
{% trans "Stats" %}
|
|
</button>
|
|
</li>
|
|
<li class="nav-item" role="presentation">
|
|
<button class="nav-link action-button" id="undefine-tab" aria-controls="undefine" data-bs-toggle="pill" data-bs-target="#undefine" type="button" role="tab" aria-selected="false">
|
|
<span id="action-block" aria-hidden="true">{% bs_icon 'trash' size='2em'%} </span>
|
|
{% trans "Destroy" %}
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
<!-- Tab panes -->
|
|
<div class="tab-content" id=mainTabMenuContent>
|
|
{% include 'instances/power_tab.html' %}
|
|
{% include 'instances/access_tab.html' %}
|
|
{% include 'instances/resize_tab.html' %}
|
|
{% if can_snapshot %}{% include 'instances/snapshots_tab.html' %}{% endif %}
|
|
{% if show_settings %}{% include 'instances/settings_tab.html' %}{% endif %}
|
|
{% include 'instances/stats_tab.html' %}
|
|
{% include 'instances/destroy_tab.html' %}
|
|
</div>
|
|
</div>
|
|
|
|
{% if app_settings.VIEW_INSTANCE_DETAIL_BOTTOM_BAR == 'True' %}
|
|
{% include 'bottom_bar.html' %}
|
|
{% endif %}
|
|
|
|
{% endblock %}
|
|
{% block script %}
|
|
<script src="{% static 'js/ace/ace.js' %}" type="text/javascript" charset="utf-8"></script>
|
|
<script>
|
|
function get_volumes(compute_id, pool) {
|
|
get_vol_url = "/computes/" + compute_id + "/storage/" + pool + "/volumes";
|
|
$.getJSON(get_vol_url, function (data) {
|
|
$("#vols").find('option').remove();
|
|
$("#vols").removeAttr("disabled");
|
|
|
|
$.each(data['vols'], function(i, item) {
|
|
$("#vols").append($("<option>").val(item).text(item));
|
|
})
|
|
});
|
|
|
|
var sto_drop = document.getElementById('select_storage');
|
|
sto_drop.value = pool;
|
|
sto_drop.textContent = pool;
|
|
var caret = document.createElement("span");
|
|
caret.className = "caret";
|
|
sto_drop.appendChild(caret);
|
|
|
|
var sto_input = document.getElementById('selected_storage');
|
|
sto_input.setAttribute('value', pool);
|
|
//sto_input.innerHTML = pool;
|
|
}
|
|
</script>
|
|
<script>
|
|
// The XML editor exists only for superusers
|
|
if (document.getElementById("editor")) {
|
|
var editor = ace.edit("editor");
|
|
editor.getSession().setMode("ace/mode/xml");
|
|
|
|
var input = $('input[name="inst_xml"]');
|
|
editor.getSession().on("change", function () {
|
|
input.val(editor.getSession().getValue());
|
|
});
|
|
}
|
|
</script>
|
|
<script>
|
|
function random_mac(net) {
|
|
$.getJSON("{% url 'instances:random_mac_address' %}", function (data) {
|
|
$('input[name="' + net + '"]').val(data['mac']);
|
|
});
|
|
}
|
|
</script>
|
|
<script>
|
|
function show_console() {
|
|
if ($('#console_show_pass').attr('type') == 'password') {
|
|
$('#console_show_pass').attr('type', 'text');
|
|
} else {
|
|
$('#console_show_pass').attr('type', 'password');
|
|
}
|
|
}
|
|
</script>
|
|
<script>
|
|
function guess_mac_address(src_elem, net) {
|
|
new_vname = $(src_elem).val();
|
|
guess_mac_address_url = "{% url 'instances:guess_mac_address' 1 %}".replace(1, new_vname);
|
|
$.getJSON(guess_mac_address_url, function(data) {
|
|
$('input[name="clone-net-mac-'+net+'"]').val(data['mac']);
|
|
});
|
|
}
|
|
</script>
|
|
<script>
|
|
function guess_clone_name() {
|
|
$.getJSON("{% url 'instances:guess_clone_name' %}", function(data) {
|
|
guessed_name = data['name'].split(".")[0];
|
|
$('#clone_name').val(guessed_name);
|
|
update_clone_disk_name(guessed_name);
|
|
guess_mac_address('#clone_name', 0);
|
|
});
|
|
}
|
|
</script>
|
|
<script>
|
|
function update_clone_disk_name(new_vname) {
|
|
vname = '{{ instance.name }}';
|
|
{% for disk in instance.disks %}
|
|
disk_name = '{{ disk.image }}';
|
|
disk_dot = disk_name.split('.');
|
|
disk_dot_suffix = disk_dot[disk_dot.length-1];
|
|
if (disk_name.startsWith(vname)) {
|
|
image = disk_name.replace(vname, new_vname);
|
|
} else if (disk_name.lastIndexOf('.') > -1 && disk_dot_suffix.length <= 7) {
|
|
disk_dot.pop();
|
|
disk_name_only = disk_dot.join('-');
|
|
image = new_vname + "-" + disk_name_only + "." + disk_dot_suffix
|
|
} else if (new_vname != disk_name) {
|
|
image = new_vname
|
|
} else {
|
|
image = new_vname + '-clone';
|
|
}
|
|
$('#disk_name-{{ disk.dev }}').val(image);
|
|
{% endfor %}
|
|
}
|
|
</script>
|
|
<script>
|
|
$(document).on('change', '#console_passwd_gen', function () {
|
|
if ($(this).prop('checked')) {
|
|
$('#console_passwd_manual').hide();
|
|
$('#console_passwd_clear').prop('checked', false);
|
|
} else {
|
|
$('#console_passwd_manual').show();
|
|
}
|
|
});
|
|
$(document).on('change', '#console_passwd_clear', function () {
|
|
if ($(this).prop('checked')) {
|
|
$('#console_passwd_manual').hide();
|
|
$('#console_passwd_gen').prop('checked', false);
|
|
} else {
|
|
$('#console_passwd_manual').show();
|
|
}
|
|
});
|
|
$(document).on('change', '#console_keymap_clear', function () {
|
|
if ($(this).prop('checked')) {
|
|
$('#console_keymap_selection').hide();
|
|
} else {
|
|
$('#console_keymap_selection').show();
|
|
}
|
|
});
|
|
$('#clone_name').on('input', function () {
|
|
update_clone_disk_name($(this).val());
|
|
});
|
|
$(document).ready(function () {
|
|
// set current console keymap or fall back to default
|
|
var keymap = "{{ instance.console_keymap }}";
|
|
if (keymap != '') {
|
|
$("#console_select_keymap option[value='" + keymap + "']").prop('selected', true);
|
|
}
|
|
});
|
|
$(document).ready(function () {
|
|
// set current console listen address or fall back to default
|
|
var console_listener_address = "{{ instance.console_listener_address }}";
|
|
if (console_listener_address != '') {
|
|
$("#console_select_listener_address option[value='" + console_listener_address + "']").prop('selected', true);
|
|
}
|
|
});
|
|
$(document).ready(function () {
|
|
// get video model or fall back to default
|
|
let video_model = "{{ instance.video_model }}";
|
|
if (video_model != '') {
|
|
$("#video_model_select option[value='" + video_model + "']").prop('selected', true);
|
|
}
|
|
});
|
|
{% if can_open_console %}
|
|
$(document).ready(function () {
|
|
// set vdi url
|
|
$.get("{% url 'vdi_url' compute.id instance.name %}", function(data) {
|
|
$("#vdi_url_input").attr("value", data);
|
|
$("#vdi_url").attr("href", data);
|
|
});
|
|
});
|
|
{% endif %}
|
|
{% if request.user.is_superuser %}
|
|
$(document).ready(function () {
|
|
random_mac('clone-net-mac-0');
|
|
random_mac('add-net-mac');
|
|
update_clone_disk_name($('#clone_name').val());
|
|
});
|
|
{% else %}
|
|
$('#select_clone_name').on('change', function () {
|
|
update_clone_disk_name($(this).val());
|
|
guess_mac_address('#select_clone_name', 0);
|
|
});
|
|
$(document).ready(function () {
|
|
update_clone_disk_name($('#select_clone_name').val());
|
|
guess_mac_address('#select_clone_name', 0);
|
|
});
|
|
{% endif %}
|
|
</script>
|
|
<script>
|
|
$(document).ready(function(){
|
|
$('[data-bs-toggle="popover"]').popover({
|
|
placement : 'top'
|
|
});
|
|
});
|
|
</script>
|
|
<script>
|
|
function set_orderlist(obj){
|
|
var result = '';
|
|
$('#b_order label input:checked').each(function () {
|
|
if (result != '') result += ',';
|
|
result += $(this).val();
|
|
});
|
|
obj.val(result);
|
|
}
|
|
$(document).ready(function () {
|
|
{# Boot Order Arragements #}
|
|
jQuery.fn.multiselect = function() {
|
|
$(this).each(function() {
|
|
var checkboxes = $(this).find("input:checkbox");
|
|
checkboxes.each(function() {
|
|
var checkbox = $(this);
|
|
// Highlight pre-selected checkboxes
|
|
if (checkbox.prop("checked"))
|
|
checkbox.parent().addClass("multiselect-on");
|
|
// Highlight checkboxes that the user selects
|
|
checkbox.click(function() {
|
|
if (checkbox.prop("checked"))
|
|
checkbox.parent().addClass("multiselect-on");
|
|
else
|
|
checkbox.parent().removeClass("multiselect-on");
|
|
});
|
|
});
|
|
});
|
|
};
|
|
$(function() {
|
|
$(".multiselect").multiselect();
|
|
});
|
|
|
|
$('#boot_order_up').bind('click', function() {
|
|
$('#b_order label input:checked').each( function() {
|
|
var label = $(this).parent();
|
|
var newPos = label.index() - 1;
|
|
if (newPos > -1) {
|
|
$('#b_order label').eq(newPos).before("<label><input type='checkbox' value='"+$(this).val()+"' name='"+$(this).val()+"' checked>"+$(this).parent().text()+"</label>");
|
|
label.remove();
|
|
}
|
|
$(".multiselect").multiselect();
|
|
});
|
|
set_orderlist($("#bootorder"));
|
|
});
|
|
|
|
$('#boot_order_down').bind('click', function() {
|
|
var countOptions = $('#b_order label').length;
|
|
var countSelected = $('#b_order label input:checked').length;
|
|
$('#b_order label input:checked').each( function() {
|
|
var label = $(this).parent();
|
|
var newPos = label.index() + countSelected;
|
|
if (newPos < countOptions) {
|
|
$('#b_order label').eq(newPos).after("<label><input type='checkbox' value='"+$(this).val()+"' name='"+$(this).val()+"' checked>"+$(this).parent().text()+"</label>");
|
|
label.remove();
|
|
}
|
|
$(".multiselect").multiselect();
|
|
});
|
|
set_orderlist($("#bootorder"));
|
|
});
|
|
});
|
|
</script>
|
|
<script>
|
|
$(function () {
|
|
$('.js-custom__checkbox').change(function () {
|
|
var container = $(this).closest('.js-custom__container');
|
|
var toggles = container.find('.js-custom__toggle');
|
|
toggles.toggle();
|
|
});
|
|
});
|
|
</script>
|
|
<script src="{% static 'js/Chart.bundle.min.js' %}"></script>
|
|
<script src="{% static 'js/poll.js' %}"></script>
|
|
<script>
|
|
var stats_tab = document.querySelector('#graphics-tab');
|
|
var stats_poll = null;
|
|
// The charts are polled while the Stats tab is shown; they are made once.
|
|
stats_tab.addEventListener('hidden.bs.tab', function (event) {
|
|
stats_poll.stop();
|
|
});
|
|
stats_tab.addEventListener('shown.bs.tab', function (event) {
|
|
if (stats_poll !== null) {
|
|
stats_poll.start();
|
|
return;
|
|
}
|
|
var cpu_ctx = $("#cpuChart").get(0).getContext("2d");
|
|
var cpuChart = new Chart(cpu_ctx, {
|
|
type: 'line',
|
|
data: {
|
|
datasets : [{
|
|
backgroundColor: "rgba(44,127,184,0.5)",
|
|
label: "Usage"
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
legend: {
|
|
display: false
|
|
},
|
|
scales: {
|
|
xAxes:[{
|
|
offset: false,
|
|
ticks: {
|
|
beginAtZero: false,
|
|
autoSkip: true,
|
|
maxTicksLimit: 10,
|
|
maxRotation: 0,
|
|
minRotation: 0,
|
|
stepSize: 10,
|
|
},
|
|
}],
|
|
yAxes: [{
|
|
ticks: {
|
|
suggestedMax: 100,
|
|
suggestedMin: 0,
|
|
stepSize: 20,
|
|
callback: function(value, index, values) {
|
|
return value + ' %';
|
|
}
|
|
},
|
|
}],
|
|
},
|
|
tooltips: {
|
|
callbacks: {
|
|
label: function (tooltipItem, chart) {
|
|
var label = chart.datasets[tooltipItem.datasetIndex].label || '';
|
|
if (label) {
|
|
label += ': ';
|
|
}
|
|
return label += tooltipItem.yLabel + ' %';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
var mem_ctx = $("#memChart").get(0).getContext("2d");
|
|
var memChart = new Chart(mem_ctx, {
|
|
type: 'line',
|
|
data: {
|
|
datasets : [{
|
|
label: "Usage"
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
legend: {
|
|
display: false
|
|
},
|
|
scales: {
|
|
xAxes:[{
|
|
offset: false,
|
|
ticks: {
|
|
beginAtZero: false,
|
|
autoSkip: true,
|
|
maxTicksLimit: 10,
|
|
maxRotation: 0,
|
|
minRotation: 0,
|
|
stepSize: 10,
|
|
},
|
|
}],
|
|
yAxes: [{
|
|
ticks: {
|
|
suggestedMax: 100,
|
|
suggestedMin: 0,
|
|
stepSize: 20,
|
|
callback: function(value, index, values) {
|
|
return value + ' MB';
|
|
}
|
|
},
|
|
}],
|
|
},
|
|
tooltips: {
|
|
callbacks: {
|
|
label: function (tooltipItem, chart) {
|
|
var label = chart.datasets[tooltipItem.datasetIndex].label || '';
|
|
if (label) {
|
|
label += '(RSS): ';
|
|
}
|
|
return label += tooltipItem.yLabel + ' MB';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
var diskChart = {};
|
|
{% for disk in instance.disks %}
|
|
var disk_ctx_{{ disk.dev }} = $("#blk{{ disk.dev }}Chart").get(0).getContext("2d");
|
|
diskChart['{{ disk.dev }}'] = new Chart(disk_ctx_{{ disk.dev }}, {
|
|
type: 'line',
|
|
data: {
|
|
datasets : [{
|
|
backgroundColor: "rgba(127,205,187,0.5)",
|
|
label: "Read"
|
|
},
|
|
{
|
|
backgroundColor: "rgba(44,127,184,0.5)",
|
|
label: "Write"
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
legend: {
|
|
display: false
|
|
},
|
|
scales: {
|
|
xAxes:[{
|
|
offset: false,
|
|
ticks: {
|
|
beginAtZero: false,
|
|
autoSkip: true,
|
|
maxTicksLimit: 10,
|
|
maxRotation: 0,
|
|
minRotation: 0,
|
|
stepSize: 10,
|
|
},
|
|
}],
|
|
yAxes: [{
|
|
ticks: {
|
|
suggestedmax: 100,
|
|
suggestedMin: 0,
|
|
callback: function(value, index, values) {
|
|
return value + ' Mb/s';
|
|
}
|
|
},
|
|
}],
|
|
},
|
|
tooltips: {
|
|
callbacks: {
|
|
label: function (tooltipItem, chart) {
|
|
var label = chart.datasets[tooltipItem.datasetIndex].label || '';
|
|
if (label) {
|
|
label += ': ';
|
|
}
|
|
return label += tooltipItem.yLabel + ' Mb/s';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
{% endfor %}
|
|
|
|
var netChart = {};
|
|
{% for net in instance.networks %}
|
|
var net_ctx_{{ forloop.counter0 }} = $("#netEth{{ forloop.counter0 }}Chart").get(0).getContext("2d");
|
|
netChart[{{ forloop.counter0 }}] = new Chart(net_ctx_{{ forloop.counter0 }}, {
|
|
type: 'line',
|
|
data: {
|
|
datasets : [
|
|
{
|
|
backgroundColor: "rgba(127,205,187,0.5)",
|
|
label: "Inbound"
|
|
},
|
|
{
|
|
backgroundColor: "rgba(44,127,184,0.5)",
|
|
label: "Outbound"
|
|
}]
|
|
},
|
|
options: {
|
|
responsive: true,
|
|
legend: {
|
|
display: false
|
|
},
|
|
scales: {
|
|
xAxes:[{
|
|
offset: false,
|
|
ticks: {
|
|
beginAtZero: false,
|
|
autoSkip: true,
|
|
maxTicksLimit: 10,
|
|
maxRotation: 0,
|
|
minRotation: 0,
|
|
stepSize: 10,
|
|
},
|
|
}],
|
|
yAxes: [{
|
|
ticks: {
|
|
suggestedMax: 100,
|
|
suggestedMin: 0,
|
|
callback: function(value, index, values) {
|
|
return value + ' Mbps';
|
|
}
|
|
},
|
|
}],
|
|
},
|
|
tooltips: {
|
|
callbacks: {
|
|
label: function (tooltipItem, chart) {
|
|
var label = chart.datasets[tooltipItem.datasetIndex].label || '';
|
|
if (label) {
|
|
label += ': ';
|
|
}
|
|
return label += tooltipItem.yLabel + ' Mbps';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
{% endfor %}
|
|
|
|
stats_poll = pollWhileVisible(10000, function () {
|
|
return $.getJSON("{% url 'instances:stats' instance.id %}");
|
|
}, function graph_usage(data) {
|
|
cpuChart.data.labels.push(data.timeline);
|
|
cpuChart.data.datasets[0].data.push(data.cpudata);
|
|
if (cpuChart.data.datasets[0].data.length > 10){
|
|
cpuChart.data.labels.shift();
|
|
cpuChart.data.datasets[0].data.shift();
|
|
}
|
|
cpuChart.update();
|
|
|
|
memChart.data.labels.push(data.timeline);
|
|
memChart.options.scales.yAxes[0].ticks.max = parseInt(data.memdata.total / 1024);
|
|
memChart.options.scales.yAxes[0].ticks.stepSize = parseInt(data.memdata.total / (1024 * 5));
|
|
memChart.data.datasets[0].data.push(data.memdata.used / 1024);
|
|
if (memChart.data.datasets[0].data.length > 10){
|
|
memChart.data.labels.shift();
|
|
memChart.data.datasets[0].data.shift();
|
|
}
|
|
memChart.update();
|
|
|
|
for (let j = 0; j < data.blkdata.length; j++) {
|
|
diskChart[data.blkdata[j].dev].data.labels.push(data.timeline);
|
|
|
|
diskChart[data.blkdata[j].dev].data.datasets[0].data.push(data.blkdata[j].data[0]);
|
|
diskChart[data.blkdata[j].dev].data.datasets[1].data.push(data.blkdata[j].data[1]);
|
|
if (diskChart[data.blkdata[j].dev].data.datasets[0].data.length > 10){
|
|
diskChart[data.blkdata[j].dev].data.labels.shift();
|
|
diskChart[data.blkdata[j].dev].data.datasets[0].data.shift();
|
|
diskChart[data.blkdata[j].dev].data.datasets[1].data.shift();
|
|
}
|
|
diskChart[data.blkdata[j].dev].update();
|
|
}
|
|
|
|
for (let j = 0; j < data.netdata.length; j++) {
|
|
netChart[data.netdata[j].dev].data.labels.push(data.timeline);
|
|
|
|
netChart[data.netdata[j].dev].data.datasets[0].data.push(data.netdata[j].data[0]);
|
|
netChart[data.netdata[j].dev].data.datasets[1].data.push(data.netdata[j].data[1]);
|
|
if (netChart[data.netdata[j].dev].data.datasets[0].data.length > 10){
|
|
netChart[data.netdata[j].dev].data.labels.shift();
|
|
netChart[data.netdata[j].dev].data.datasets[0].data.shift();
|
|
netChart[data.netdata[j].dev].data.datasets[1].data.shift();
|
|
}
|
|
netChart[data.netdata[j].dev].update();
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
<script>
|
|
backgroundJobRunning = false;
|
|
// not "status": that is window.status, which the browser may not keep
|
|
var vm_status = {{ instance.status|lower }};
|
|
var status_poll = pollWhileVisible(5000, function () {
|
|
return $.getJSON("{% url 'instances:status' instance.id %}");
|
|
}, function get_status(data) {
|
|
if (data['status'] != vm_status && !backgroundJobRunning) {
|
|
window.location.reload()
|
|
}
|
|
});
|
|
|
|
// Stop getting status info before delete instance
|
|
$('#delete_form').submit(function(){
|
|
status_poll.stop();
|
|
return true;
|
|
});
|
|
</script>
|
|
<script>
|
|
// Open the tab (and sub-tab) a redirect points to with #<pane id>
|
|
function show_tab(target) {
|
|
var button = document.querySelector('button[data-bs-target="' + target + '"]');
|
|
if (button) {
|
|
bootstrap.Tab.getOrCreateInstance(button).show();
|
|
}
|
|
}
|
|
var hash = location.hash;
|
|
var parents = {
|
|
'#poweron': '#power', '#poweroff': '#power', '#powercycle': '#power', '#suspend': '#power', '#resume': '#power',
|
|
'#resizevm_cpu': '#resize', '#resizevm_mem': '#resize', '#resizevm_disk': '#resize',
|
|
'#boot_opt': '#settings', '#disks': '#settings', '#network': '#settings', '#clone': '#settings',
|
|
'#xmledit': '#settings', '#vncsettings': '#settings', '#migrate': '#settings', '#options': '#settings',
|
|
'#users': '#settings',
|
|
'#takesnapshot': '#snapshots', '#takeextsnapshot': '#snapshots', '#managesnapshot': '#snapshots'
|
|
};
|
|
if (hash === '#resize') {
|
|
show_tab('#resize');
|
|
} else if (parents[hash]) {
|
|
show_tab(parents[hash]);
|
|
show_tab(hash);
|
|
}
|
|
// Settings opens on its first section the user has (Boot is superuser-only)
|
|
var settings_tabs = document.querySelector('#settings .nav-tabs');
|
|
if (settings_tabs && !settings_tabs.querySelector('.nav-link.active')) {
|
|
var first = settings_tabs.querySelector('.nav-link:not(#osinfo-tab)');
|
|
if (first) {
|
|
bootstrap.Tab.getOrCreateInstance(first).show();
|
|
}
|
|
}
|
|
</script>
|
|
<script>
|
|
function get_osinfo() {
|
|
show_tab('#settings');
|
|
show_tab('#osinfo');
|
|
|
|
$.getJSON("{% url 'instances:osinfo' instance.id %}", function (data) {
|
|
$.each(data, function() {
|
|
$('#oshostname').text(data['host-name']);
|
|
$('#osname').text(data.id);
|
|
$('#osprettyname').text(data['pretty-name']);
|
|
$('#oskernelrelease').text(data['kernel-release']);
|
|
$('#oskernelversion').text(data['kernel-version']);
|
|
$('#osversion').text(data.version);
|
|
$('#ostimezone').text(data.zone + " / " + data.offset);
|
|
})
|
|
});
|
|
}
|
|
</script>
|
|
{% endblock %}
|