1
0
mirror of https://github.com/mailcow/mailcow-dockerized.git synced 2026-06-11 17:10:28 +00:00

[Agent] Replace dockerapi container with Redis-based control bus

This commit is contained in:
FreddleSpl0it
2026-05-20 20:54:51 +02:00
parent 4ddcee28e4
commit 689d753264
75 changed files with 3740 additions and 2462 deletions
+6 -6
View File
@@ -277,19 +277,19 @@ $(document).ready(function() {
// trigger container restart
$('#RestartContainer').on('show.bs.modal', function(e) {
var container = $(e.relatedTarget).data('container');
$('#containerName').text(container);
$('#triggerRestartContainer').click(function(){
var node = $(e.relatedTarget).data('node') || '';
$('#containerName').text(container + (node ? ' / ' + node : ''));
$('#triggerRestartContainer').off('click').on('click', function(){
$(this).prop("disabled",true);
$(this).html('<div class="spinner-border text-white" role="status"><span class="visually-hidden">Loading...</span></div>');
$('#statusTriggerRestartContainer').html(lang_footer.restarting_container);
var payload = { 'service': container, 'action': 'restart' };
if (node) payload.node = node;
$.ajax({
method: 'get',
url: '/inc/ajax/container_ctrl.php',
timeout: docker_timeout,
data: {
'service': container,
'action': 'restart'
}
data: payload
})
.always( function (data, status) {
$('#statusTriggerRestartContainer').append(data);
+61 -163
View File
@@ -23,8 +23,6 @@ $(document).ready(function() {
}
});
// set update loop container list
containersToUpdate = {};
// set default ChartJs Font Color
Chart.defaults.color = '#999';
// create host cpu and mem charts
@@ -72,7 +70,6 @@ $(document).ready(function() {
$("#host_show_ip").find(".spinner-border").addClass("d-none");
});
});
update_container_stats();
});
jQuery(function($){
if (localStorage.getItem("current_page") === null) {
@@ -210,6 +207,11 @@ jQuery(function($){
data: 'priority',
defaultContent: ''
},
{
title: lang_debug.node,
data: 'node',
defaultContent: '-'
},
{
title: lang.message,
data: 'message',
@@ -692,6 +694,11 @@ jQuery(function($){
data: 'priority',
defaultContent: ''
},
{
title: lang_debug.node,
data: 'node',
defaultContent: '-'
},
{
title: lang.message,
data: 'message',
@@ -747,6 +754,11 @@ jQuery(function($){
data: 'priority',
defaultContent: ''
},
{
title: lang_debug.node,
data: 'node',
defaultContent: '-'
},
{
title: lang.message,
data: 'message',
@@ -802,6 +814,11 @@ jQuery(function($){
data: 'priority',
defaultContent: ''
},
{
title: lang_debug.node,
data: 'node',
defaultContent: '-'
},
{
title: lang.message,
data: 'message',
@@ -862,6 +879,11 @@ jQuery(function($){
data: 'priority',
defaultContent: ''
},
{
title: lang_debug.node,
data: 'node',
defaultContent: '-'
},
{
title: lang.message,
data: 'message',
@@ -1292,52 +1314,6 @@ jQuery(function($){
// start polling host stats if tab is active
onVisible("[id^=tab-containers]", () => update_stats());
// start polling container stats if collapse is active
var containerElements = document.querySelectorAll(".container-details-collapse");
for (let i = 0; i < containerElements.length; i++){
new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if(entry.intersectionRatio > 0) {
if (!containerElements[i].classList.contains("show")){
var container = containerElements[i].id.replace("Collapse", "");
var container_id = containerElements[i].getAttribute("data-id");
// check if chart exists or needs to be created
if (!Chart.getChart(container + "_DiskIOChart"))
createReadWriteChart(container + "_DiskIOChart", "Read", "Write");
if (!Chart.getChart(container + "_NetIOChart"))
createReadWriteChart(container + "_NetIOChart", "Recv", "Sent");
// add container to polling list
containersToUpdate[container] = {
id: container_id,
state: "idle"
}
// stop polling if collapse is closed
containerElements[i].addEventListener('hidden.bs.collapse', function () {
var diskIOCtx = Chart.getChart(container + "_DiskIOChart");
var netIOCtx = Chart.getChart(container + "_NetIOChart");
diskIOCtx.data.datasets[0].data = [];
diskIOCtx.data.datasets[1].data = [];
diskIOCtx.data.labels = [];
netIOCtx.data.datasets[0].data = [];
netIOCtx.data.datasets[1].data = [];
netIOCtx.data.labels = [];
diskIOCtx.update();
netIOCtx.update();
delete containersToUpdate[container];
});
}
}
});
}).observe(containerElements[i]);
}
});
@@ -1351,127 +1327,49 @@ function update_stats(timeout=5){
window.fetch("/api/v1/get/status/host", {method:'GET',cache:'no-cache'}).then(function(response) {
return response.json();
}).then(function(data) {
if (data){
// display table data
$("#host_date").text(data.system_time);
$("#host_uptime").text(formatUptime(data.uptime));
$("#host_cpu_cores").text(data.cpu.cores);
$("#host_cpu_usage").text(parseInt(data.cpu.usage).toString() + "%");
$("#host_memory_total").text((data.memory.total / (1024 ** 3)).toFixed(2).toString() + "GB");
$("#host_memory_usage").text(parseInt(data.memory.usage).toString() + "%");
$("#host_architecture").html(data.architecture);
// update cpu and mem chart
var cpu_chart = Chart.getChart("host_cpu_chart");
var mem_chart = Chart.getChart("host_mem_chart");
// Wrapped in try/catch so a malformed payload doesn't break the
// polling loop forever. We always reschedule from .finally.
try {
if (data && data.cpu && data.memory){
$("#host_date").text(data.system_time || "");
$("#host_uptime").text(formatUptime(data.uptime));
$("#host_cpu_cores").text(data.cpu.cores);
$("#host_cpu_usage").text(parseInt(data.cpu.usage).toString() + "%");
$("#host_memory_total").text((data.memory.total / (1024 ** 3)).toFixed(2).toString() + "GB");
$("#host_memory_usage").text(parseInt(data.memory.usage).toString() + "%");
$("#host_architecture").html(data.architecture);
cpu_chart.data.labels.push(data.system_time.split(" ")[1]);
if (cpu_chart.data.labels.length > 30) cpu_chart.data.labels.shift();
mem_chart.data.labels.push(data.system_time.split(" ")[1]);
if (mem_chart.data.labels.length > 30) mem_chart.data.labels.shift();
var cpu_chart = Chart.getChart("host_cpu_chart");
var mem_chart = Chart.getChart("host_mem_chart");
cpu_chart.data.datasets[0].data.push(data.cpu.usage);
if (cpu_chart.data.datasets[0].data.length > 30) cpu_chart.data.datasets[0].data.shift();
mem_chart.data.datasets[0].data.push(data.memory.usage);
if (mem_chart.data.datasets[0].data.length > 30) mem_chart.data.datasets[0].data.shift();
if (cpu_chart && mem_chart && typeof data.system_time === "string") {
var label = data.system_time.split(" ")[1] || "";
cpu_chart.data.labels.push(label);
if (cpu_chart.data.labels.length > 30) cpu_chart.data.labels.shift();
mem_chart.data.labels.push(label);
if (mem_chart.data.labels.length > 30) mem_chart.data.labels.shift();
cpu_chart.update();
mem_chart.update();
cpu_chart.data.datasets[0].data.push(data.cpu.usage);
if (cpu_chart.data.datasets[0].data.length > 30) cpu_chart.data.datasets[0].data.shift();
mem_chart.data.datasets[0].data.push(data.memory.usage);
if (mem_chart.data.datasets[0].data.length > 30) mem_chart.data.datasets[0].data.shift();
cpu_chart.update();
mem_chart.update();
}
} else {
console.warn("update_stats: unexpected host payload", data);
}
} catch (e) {
console.warn("update_stats: render error", e);
}
// run again in n seconds
}).catch(function(e) {
console.warn("update_stats: fetch failed", e);
}).finally(function() {
// Always reschedule so a transient backend hiccup can't kill the poll loop.
setTimeout(update_stats, timeout * 1000);
});
}
// update specific container stats - every n (default 5s) seconds
function update_container_stats(timeout=5){
if ($('#tab-containers').hasClass('active')) {
for (let container in containersToUpdate){
container_id = containersToUpdate[container].id;
// check if container update stats is already running
if (containersToUpdate[container].state == "running")
continue;
containersToUpdate[container].state = "running";
window.fetch("/api/v1/get/status/container/" + container_id, {method:'GET',cache:'no-cache'}).then(function(response) {
return response.json();
}).then(function(data) {
var diskIOCtx = Chart.getChart(container + "_DiskIOChart");
var netIOCtx = Chart.getChart(container + "_NetIOChart");
prev_stats = null;
if (data.length >= 2){
prev_stats = data[data.length -2];
// hide spinners if we collected enough data
$('#' + container + "_DiskIOChart").removeClass('d-none');
$('#' + container + "_DiskIOChart").prev().addClass('d-none');
$('#' + container + "_NetIOChart").removeClass('d-none');
$('#' + container + "_NetIOChart").prev().addClass('d-none');
}
data = data[data.length -1];
if (prev_stats != null){
// calc time diff
var time_diff = (new Date(data.read) - new Date(prev_stats.read)) / 1000;
// calc disk io b/s
if ('io_service_bytes_recursive' in prev_stats.blkio_stats && prev_stats.blkio_stats.io_service_bytes_recursive !== null){
var prev_read_bytes = 0;
var prev_write_bytes = 0;
for (var i = 0; i < prev_stats.blkio_stats.io_service_bytes_recursive.length; i++){
if (prev_stats.blkio_stats.io_service_bytes_recursive[i].op == "read")
prev_read_bytes = prev_stats.blkio_stats.io_service_bytes_recursive[i].value;
else if (prev_stats.blkio_stats.io_service_bytes_recursive[i].op == "write")
prev_write_bytes = prev_stats.blkio_stats.io_service_bytes_recursive[i].value;
}
var read_bytes = 0;
var write_bytes = 0;
for (var i = 0; i < data.blkio_stats.io_service_bytes_recursive.length; i++){
if (data.blkio_stats.io_service_bytes_recursive[i].op == "read")
read_bytes = data.blkio_stats.io_service_bytes_recursive[i].value;
else if (data.blkio_stats.io_service_bytes_recursive[i].op == "write")
write_bytes = data.blkio_stats.io_service_bytes_recursive[i].value;
}
var diff_bytes_read = (read_bytes - prev_read_bytes) / time_diff;
var diff_bytes_write = (write_bytes - prev_write_bytes) / time_diff;
}
// calc net io b/s
if ('networks' in prev_stats){
var prev_recv_bytes = 0;
var prev_sent_bytes = 0;
for (var key in prev_stats.networks){
prev_recv_bytes += prev_stats.networks[key].rx_bytes;
prev_sent_bytes += prev_stats.networks[key].tx_bytes;
}
var recv_bytes = 0;
var sent_bytes = 0;
for (var key in data.networks){
recv_bytes += data.networks[key].rx_bytes;
sent_bytes += data.networks[key].tx_bytes;
}
var diff_bytes_recv = (recv_bytes - prev_recv_bytes) / time_diff;
var diff_bytes_sent = (sent_bytes - prev_sent_bytes) / time_diff;
}
addReadWriteChart(diskIOCtx, diff_bytes_read, diff_bytes_write, "");
addReadWriteChart(netIOCtx, diff_bytes_recv, diff_bytes_sent, "");
}
// run again in n seconds
containersToUpdate[container].state = "idle";
}).catch(err => {
console.log(err);
});
}
}
// run again in n seconds
setTimeout(update_container_stats, timeout * 1000);
}
// format hosts uptime seconds to readable string
function formatUptime(seconds){
seconds = Number(seconds);