lxconsole/lxconsole/templates/containers.html

332 lines
12 KiB
HTML

{% extends "main.html" %}
{% block header %}
<div class="row mb-2">
<div class="col-sm-6">
<h1>{{ page_title | safe }}</h1>
</div>
<div class="col-sm-6">
<a class="btn btn-outline-primary float-sm-right mr-4" href="#" data-toggle="modal" data-target="#addModal" title="Add Container" aria-hidden="true">
<i class="fas fa-plus fa-sm fa-fw"></i> Container
</a>
</div>
</div>
{% endblock header %}
{% block content %}
<div class="col-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">Containers</h3>
<div class="card-tools">
<button type="button" class="btn btn-tool" onclick="reloadPageContent()" title="Refresh">
<i class="fas fa-sync"></i>
</button>
</div>
</div>
<div class="card-body">
<table class="table table-hover" id="myDataTable" width="100%" cellspacing="0">
</table>
</div>
</div>
</div>
{% endblock content %}
{% block modal %}
{% include 'modals/containers.html' %}
{% endblock modal %}
{% block script %}
<script>
var reloadTime = 10000;
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
const serverId = urlParams.get('id');
const project = urlParams.get('project');
var editedContainer = ''
applySidebarStyles();
applySidebarLinks();
populateSidebarLinks();
populateNavbarLinks();
function reloadPageContent() {
//Clear the automatic page reload
clearTimeout(pageReloadTimeout);
//Reload the datatables content
$('#myDataTable').DataTable().ajax.reload(null, false);
//Set the automatic page reload
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
function loadPageContent(){
//Display the current project
$("#selectedProject").text(project);
//Populate the Server dropdown
$.getJSON("../api/servers/list_servers?id="+serverId, function (data) {
data = data.data
for (var index = 0; index < data.length; index++) {
if (data[index].name == '')
optionText = data[index].addr
else
optionText = data[index].name
if (data[index].id == serverId)
$('#serverListNav').append('<option value="' + data[index].id + '" selected="selected">' + optionText + '</option>');
else
$('#serverListNav').append('<option value="' + data[index].id + '">' + optionText + '</option>');
}
})
//Populate the Project dropdown
$.getJSON("../api/projects/list_projects?id="+serverId+"&project="+project, function (data) {
data = data.metadata
for (var index = 0; index < data.length; index++) {
optionText = data[index].replace('/1.0/projects/','');
if (optionText == project)
$('#projectListNav').append('<option value="' + optionText + '" selected="selected">' + optionText + '</option>');
else
$('#projectListNav').append('<option value="' + optionText + '">' + optionText + '</option>');
}
})
//Populate the modal Profile dropdown
$.getJSON("../api/profiles/list_profiles?id="+serverId+"&project="+project, function (data) {
data = data.metadata
for (var index = 0; index < data.length; index++) {
//When using projects other than default and no recursion, it gets like URL variable with "?"
optionText = data[index].split("?")
optionText = optionText[0].replace('/1.0/profiles/','');
if (optionText == 'default') {
$('#containerProfileInput').append('<option value="' + optionText + '" selected="selected">' + optionText + '</option>');
}
else {
$('#containerProfileInput').append('<option value="' + optionText + '">' + optionText + '</option>');
}
}
})
//Populate the modal Location dropdown
$.getJSON("../api/cluster-members/list_cluster_members?id="+serverId+"&project="+project, function (data) {
data = data.metadata
for (var index = 0; index < data.length; index++) {
optionText = data[index].replace('/1.0/cluster/members/','');
$('#containerLocationInput').append('<option value="' + optionText + '">' + optionText + '</option>');
}
})
$.getJSON("../api/cluster-groups/list_cluster_groups?id="+serverId+"&project="+project, function (data) {
data = data.metadata
for (var index = 0; index < data.length; index++) {
optionText = data[index].replace('/1.0/cluster/groups/','');
$('#containerLocationInput').append('<option value="@' + optionText + '">@' + optionText + '</option>');
}
})
//Populate the modal Image dropdown
$.getJSON("../api/images/list_images?id="+serverId+"&project="+project+"&recursion=1", function (data) {
data = data.metadata
for (var index = 0; index < data.length; index++) {
// Earlier versions of LXD did not have type property. These only supported container type instances
if (data[index].hasOwnProperty('type')) {
if(data[index].type == 'container'){
$('#containerImageInput').append('<option value="' + data[index].fingerprint + '">' + data[index].properties.description + '</option>');
}
}
else {
$('#containerImageInput').append('<option value="' + data[index].fingerprint + '">' + data[index].properties.description + '</option>');
}
}
})
// Configure Datatable
$('#myDataTable').DataTable({
ajax: {
url: "../api/containers/list_instances?id="+serverId+"&project=" + project + "&recursion=2",
dataType: "json",
dataSrc: "metadata",
contentType: "application/json"
},
columns: [
{ title: "Name", data: function (row, type, set) {
if (row.hasOwnProperty('name')) {
if (row.name)
return '<a href="../container?id=' + serverId + '&project=' + project + '&instance=' + row.name + '">' + row.name + '</a>';
}
return '-'
},
},
{ title: "OS", data: function (row, type, set) {
if (row.hasOwnProperty('expanded_config')) {
if (row.expanded_config.hasOwnProperty('image.os')) {
if (row.expanded_config['image.os']){
return row.expanded_config['image.os']
}
}
}
return '-'
},
},
{ title: "Location", data: function (row, type, set) {
if (row.hasOwnProperty('location')) {
if (row.location){
return row.location
}
}
return '-'
},
},
{ title: "IPv4", data: function (row, type, set) {
if (row.hasOwnProperty('ipv4_addresses')) {
if (row.ipv4_addresses.length > 0){
return row.ipv4_addresses.join(', <br />')
}
}
return '-'
},
},
{ title: "IPv6", data: function (row, type, set) {
if (row.hasOwnProperty('ipv6_addresses')) {
if (row.ipv6_addresses.length > 0){
return row.ipv6_addresses.join(', <br />')
}
}
return '-'
},
},
{ title: "Memory", data: function (row, type, set) {
if (row.hasOwnProperty('memory')) {
if (row.memory){
if (type === 'display'){
return (row.memory / 1024 / 1024).toFixed(2) + ' MiB'
}
return row.memory
}
}
return '-'
},
},
{ title: "Root Disk", data: function (row, type, set) {
if (row.hasOwnProperty('disk')) {
if (row.disk){
if (type === 'display'){
return (row.disk / 1024 / 1024).toFixed(2) + ' MiB'
}
return row.disk
}
}
return '-'
},
},
{ title: "Status", data: function (row, type, set) {
if (row.hasOwnProperty('status')) {
if (row.status){
return row.status
}
}
return '-'
},
},
{ title: "Actions", data: function (row, type, set) {
links = ''
if (row.hasOwnProperty('name') && row.hasOwnProperty('status')) {
if (row.name && row.status){
if (row.status == 'Frozen')
links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'unfreeze\')><i class="fas fa-pause fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
else if (row.status == 'Stopped')
links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'start\')><i class="fas fa-play fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
else if (row.status == 'Running')
links += '<a href="#" onclick=changeItemState(\''+row.name+'\',\'stop\')><i class="fas fa-stop fa-lg" style="color:#ddd" title="Edit" aria-hidden="true"></i></a>'
links += '&nbsp' + '&nbsp'
links += '<a href="#" onclick=deleteInstance(\''+row.name+'\')><i class="fas fa-trash-alt fa-lg" style="color:#ddd" title="Delete" aria-hidden="true"></i></a>'
}
}
return links
},
},
],
order: [],
});
//Set reload page content
pageReloadTimeout = setTimeout(() => { reloadPageContent(); }, reloadTime);
}
// Change state start/stop of instance
function changeItemState(name, action){
console.log("Info: starting container " + name);
$.post("../api/containers/change_instance_state?id=" + serverId + "&project=" + project, { name: name, action: action }, function (data) {
console.log(data);
if (data.error_code >= 400){
alert(data.error);
}
//Async type
setTimeout(() => { reloadPageContent(); }, 2000);
operationStatusCheck()
});
}
// Add instance
function addItem(){
console.log("Info: adding new container");
data = $('#addForm').serialize();
$.post("../api/containers/add_instance?id="+serverId+"&project="+project, data, function (data) {
console.log(data);
if (data.error_code >= 400){
alert(data.error);
}
//Aync type
setTimeout(() => { reloadPageContent(); }, 2000);
operationStatusCheck()
});
}
// Delete instance
function deleteInstance(name){
console.log("Info: confirming deletion of container " + name);
if (confirm("Are you sure you want to delete container " + name + "?") == true) {
console.log("Info: deleting container " + name);
$.post("../api/containers/delete_instance?id=" + serverId + "&project=" + project, { name: name }, function (data) {
console.log(data);
if (data.error_code >= 400){
alert(data.error);
}
//Async type
setTimeout(() => { reloadPageContent(); }, 2000);
operationStatusCheck()
});
}
}
// Create instance from JSON
function createItemUsingJSON(){
var json = $("#jsonCreateInput").val();
console.log("Info: adding new instance");
$.post("../api/containers/add_instance?id="+serverId+"&project="+project, { json: json }, function (data) {
console.log(data);
if (data.error_code >= 400){
alert(data.error);
}
//Async type
setTimeout(() => { reloadPageContent(); }, 2000);
operationStatusCheck()
});
}
$(document).ready(function(){
//If id or project variables are missing redirect to servers page
if (!serverId || !project) {
window.location.href = 'servers';
}
else {
loadPageContent()
operationStatusCheck()
}
});
</script>
{% endblock script %}