mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
On an active VM the boot order editor, the video model select and the console form showed the running VM: a pending boot order, video model or console setting looked unset, and the boot order editor offered devices of the running VM only. Choosing one of those cleared the pending order, since the setter dropped the old order and skipped devices it could not find. They now read the persistent definition (get_bootmenu, get_bootorder, get_media_devices, get_video_model and the console getters take config=), and set_bootorder refuses a device that is not in it before it changes anything.
722 lines
29 KiB
HTML
722 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.config_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.config_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.config_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>
|
|
{% trans "average over" as average_over %}
|
|
var stats_tab = document.querySelector('#graphics-tab');
|
|
var stats_poll = null;
|
|
// the seconds each CPU point averages
|
|
var cpuWindows = [];
|
|
// the usage sample of the previous answer: the next one averages since then
|
|
var statsSample = 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 += ': ';
|
|
}
|
|
label += tooltipItem.yLabel + ' %';
|
|
var span = cpuWindows[tooltipItem.index];
|
|
return span ? label + ' ({{ average_over|escapejs }} ' + span + ' s)' : label;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
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 %}
|
|
|
|
// the first point at once, then every 5 s like the host graph
|
|
stats_poll = pollWhileVisible(5000, function () {
|
|
return $.getJSON("{% url 'instances:stats' instance.id %}", statsSample ? {sample: statsSample} : {})
|
|
.fail(function () {
|
|
statsSample = null;
|
|
});
|
|
}, function graph_usage(data) {
|
|
statsSample = data.sample || null;
|
|
cpuChart.data.labels.push(data.timeline);
|
|
cpuChart.data.datasets[0].data.push(data.cpudata);
|
|
cpuWindows.push(data.window);
|
|
if (cpuChart.data.datasets[0].data.length > 10){
|
|
cpuChart.data.labels.shift();
|
|
cpuChart.data.datasets[0].data.shift();
|
|
cpuWindows.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();
|
|
|
|
// a disk or NIC added after the page loaded has no chart until a reload
|
|
function push(chart, values) {
|
|
if (!chart) {
|
|
return;
|
|
}
|
|
chart.data.labels.push(data.timeline);
|
|
chart.data.datasets[0].data.push(values[0]);
|
|
chart.data.datasets[1].data.push(values[1]);
|
|
if (chart.data.datasets[0].data.length > 10){
|
|
chart.data.labels.shift();
|
|
chart.data.datasets[0].data.shift();
|
|
chart.data.datasets[1].data.shift();
|
|
}
|
|
chart.update();
|
|
}
|
|
data.blkdata.forEach(function (disk) { push(diskChart[disk.dev], disk.data); });
|
|
data.netdata.forEach(function (nic) { push(netChart[nic.dev], nic.data); });
|
|
}, 0);
|
|
});
|
|
</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 src="{% static 'js/instance_tabs.js' %}"></script>
|
|
<script>
|
|
// Open the tab whose control targets "#<pane id>"
|
|
function show_tab(target) {
|
|
var controls = document.querySelectorAll('[data-bs-target], a[data-bs-toggle][href]');
|
|
for (var i = 0; i < controls.length; i++) {
|
|
var c = controls[i];
|
|
if ((c.getAttribute('data-bs-target') || c.getAttribute('href')) === target) {
|
|
bootstrap.Tab.getOrCreateInstance(c).show();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
// after the whole page is parsed: load_osinfo is defined further down
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
restoreInstanceTab(document, location.hash, show_tab, load_osinfo);
|
|
});
|
|
</script>
|
|
<script>
|
|
function get_osinfo() {
|
|
show_tab('#settings');
|
|
show_tab('#osinfo');
|
|
load_osinfo();
|
|
}
|
|
function load_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 %}
|