From 5e8c085446603785f4d58aafc741622f41a72d19 Mon Sep 17 00:00:00 2001 From: Raven Scott Date: Mon, 2 Dec 2024 05:05:43 -0500 Subject: [PATCH] streamline --- app.js | 11 +-- libs/templateDeploy.js | 46 +---------- server/server.js | 174 ++++++++++++++++++++--------------------- 3 files changed, 90 insertions(+), 141 deletions(-) diff --git a/app.js b/app.js index 10202db..f6b3bf7 100644 --- a/app.js +++ b/app.js @@ -64,7 +64,7 @@ function startStatsInterval() { if (window.activePeer) { const now = Date.now(); if (now - lastStatsUpdate >= 500) { // Ensure at least 500ms between updates - sendCommand('stats', {}); // Adjust command if necessary + // sendCommand('allStats', {}); // Adjust command if necessary lastStatsUpdate = now; } } else { @@ -334,12 +334,9 @@ function handlePeerData(data, topicId, peer) { // Delegate handling based on the response type switch (response.type) { - case 'stats': - console.log('[INFO] Updating container stats...'); - const stats = response.data; - stats.ip = stats.ip || 'No IP Assigned'; // Add a fallback for missing IPs - console.log(`[DEBUG] Passing stats to updateContainerStats: ${JSON.stringify(stats, null, 2)}`); - updateContainerStats(stats); + case 'allStats': + console.log('[INFO] Received aggregated stats for all containers.'); + response.data.forEach((stats) => updateContainerStats(stats)); break; case 'containers': diff --git a/libs/templateDeploy.js b/libs/templateDeploy.js index 36f9ed5..c10e55d 100644 --- a/libs/templateDeploy.js +++ b/libs/templateDeploy.js @@ -229,62 +229,18 @@ deployForm.addEventListener('submit', async (e) => { // Wait for a specific response // Wait for the specific response - const successResponse = await waitForSpecificResponse("deployed successfully", 90000); - - console.log('[INFO] Waiting for the deployment response...' + successResponse); console.log('[INFO] Deployment success:', successResponse); hideStatusIndicator(); showAlert('success', successResponse.message); - startStatsInterval(); } catch (error) { console.error('[ERROR] Failed to deploy container:', error.message); hideStatusIndicator(); showAlert('danger', error.message); } }); - -// Utility function to wait for a specific response -function waitForSpecificResponse(expectedMessageFragment, timeout = 90000) { - return new Promise((resolve, reject) => { - const startTime = Date.now(); - - function handleResponse(event) { - const response = event.detail; // Extract the response data - console.log('[DEBUG] Received response:', response); - - if (response?.success && response.message.includes(expectedMessageFragment)) { - console.log('[DEBUG] Expected response received:', response.message); - window.removeEventListener('responseReceived', handleResponse); // Remove listener - resolve(response); // Resolve with the response - } - } - - // Timeout handler - const timeoutId = setTimeout(() => { - console.warn('[WARN] Timeout while waiting for the expected response.'); - window.removeEventListener('responseReceived', handleResponse); // Cleanup - reject(new Error('Timeout waiting for the expected response')); - }, timeout); - - // Attach listener - window.addEventListener('responseReceived', handleResponse); - - // Ensure cleanup on successful resolution - const wrappedResolve = (response) => { - clearTimeout(timeoutId); - resolve(response); - }; - - // Replace `resolve` in `handleResponse` for proper cleanup - handleResponse.wrappedResolve = wrappedResolve; - }); -} - - - // Initialize templates on load document.addEventListener('DOMContentLoaded', fetchTemplates); // Export required functions -export { fetchTemplates, displayTemplateList, openDeployModal }; +export { fetchTemplates, displayTemplateList, openDeployModal }; \ No newline at end of file diff --git a/server/server.js b/server/server.js index 60b731c..cd2b7bd 100644 --- a/server/server.js +++ b/server/server.js @@ -206,7 +206,9 @@ swarm.on('connection', (peer) => { await docker.getContainer(parsedData.args.id).start(); response = { success: true, message: `Container ${parsedData.args.id} started` }; break; - + // case 'allStats': + // await handleallStatsRequest(peer); + // return; // No further response needed case 'stopContainer': console.log(`[INFO] Handling 'stopContainer' command for container: ${parsedData.args.id}`); await docker.getContainer(parsedData.args.id).stop(); @@ -528,44 +530,6 @@ docker.listContainers({ all: true }, async (err, containers) => { ipAddress = networks[0].IPAddress; // Use the first network's IP } } - - // Start streaming container stats - container.stats({ stream: true }, (statsErr, stream) => { - if (statsErr) { - console.error(`[ERROR] Failed to get stats for container ${containerInfo.Id}: ${statsErr.message}`); - return; - } - - stream.on('data', (data) => { - try { - const stats = JSON.parse(data.toString()); - const cpuUsage = calculateCPUPercent(stats); - const memoryUsage = stats.memory_stats.usage || 0; // Default to 0 if undefined - - const statsData = { - id: containerInfo.Id, - cpu: cpuUsage, - memory: memoryUsage, - ip: ipAddress, // Use the pre-inspected IP address - }; - - // Broadcast stats to all connected peers - for (const peer of connectedPeers) { - peer.write(JSON.stringify({ type: 'stats', data: statsData })); - } - } catch (parseErr) { - // console.error(`[ERROR] Failed to parse stats for container ${containerInfo.Id}: ${parseErr.message}`); - } - }); - - stream.on('error', (streamErr) => { - // console.error(`[ERROR] Stats stream error for container ${containerInfo.Id}: ${streamErr.message}`); - }); - - stream.on('close', () => { - // console.log(`[INFO] Stats stream closed for container ${containerInfo.Id}`); - }); - }); }); }); }); @@ -672,63 +636,95 @@ function handleKillTerminal(containerId, peer) { } } -function streamContainerStats(containerInfo) { +async function collectContainerStats(containerStats) { + const currentContainers = await docker.listContainers({ all: true }); + const currentIds = currentContainers.map((c) => c.Id); + + // Collect stats for all containers, including newly added ones + for (const containerInfo of currentContainers) { + if (!containerStats[containerInfo.Id]) { + console.log(`[INFO] Found new container: ${containerInfo.Names[0]?.replace(/^\//, '')}`); + containerStats[containerInfo.Id] = await initializeContainerStats(containerInfo); + } + } + + // Remove containers that no longer exist + Object.keys(containerStats).forEach((id) => { + if (!currentIds.includes(id)) { + console.log(`[INFO] Removing stats tracking for container: ${id}`); + delete containerStats[id]; + } + }); + + return containerStats; +} + +async function initializeContainerStats(containerInfo) { const container = docker.getContainer(containerInfo.Id); - // Use the same logic as listContainers to get the IP address - container.inspect((inspectErr, details) => { - let ipAddress = 'No IP Assigned'; // Default IP address fallback + // Inspect container for IP address + let ipAddress = 'No IP Assigned'; + try { + const details = await container.inspect(); + const networks = details.NetworkSettings?.Networks || {}; + ipAddress = Object.values(networks)[0]?.IPAddress || 'No IP Assigned'; + } catch (err) { + console.error(`[ERROR] Failed to inspect container ${containerInfo.Id}: ${err.message}`); + } - if (inspectErr) { - console.error(`[ERROR] Failed to inspect container ${containerInfo.Id}: ${inspectErr.message}`); - } else if (details.NetworkSettings && details.NetworkSettings.Networks) { - const networks = Object.values(details.NetworkSettings.Networks); - if (networks.length > 0 && networks[0].IPAddress) { - ipAddress = networks[0].IPAddress; // Retrieve the first network's IP address + const statsData = { + id: containerInfo.Id, + name: containerInfo.Names[0]?.replace(/^\//, '') || 'Unknown', + cpu: 0, + memory: 0, + ip: ipAddress, + }; + + // Start streaming stats for the container + try { + const statsStream = await container.stats({ stream: true }); + statsStream.on('data', (data) => { + try { + const stats = JSON.parse(data.toString()); + statsData.cpu = calculateCPUPercent(stats); + statsData.memory = stats.memory_stats.usage || 0; + } catch (err) { + console.error(`[ERROR] Failed to parse stats for container ${containerInfo.Id}: ${err.message}`); } - } - - // Start streaming container stats - container.stats({ stream: true }, (statsErr, stream) => { - if (statsErr) { - console.error(`[ERROR] Failed to get stats for container ${containerInfo.Id}: ${statsErr.message}`); - return; - } - - stream.on('data', (data) => { - try { - const stats = JSON.parse(data.toString()); - const cpuUsage = calculateCPUPercent(stats); - const memoryUsage = stats.memory_stats.usage || 0; // Default to 0 if undefined - - // Use the extracted IP address in the stats data - const statsData = { - id: containerInfo.Id, - cpu: cpuUsage, - memory: memoryUsage, - ip: ipAddress, // Use the IP address retrieved during inspection - }; - - // Broadcast stats to all connected peers - for (const peer of connectedPeers) { - peer.write(JSON.stringify({ type: 'stats', data: statsData })); - } - } catch (parseErr) { - console.error(`[ERROR] Failed to parse stats for container ${containerInfo.Id}: ${parseErr.message}`); - } - }); - - stream.on('error', (streamErr) => { - console.error(`[ERROR] Stats stream error for container ${containerInfo.Id}: ${streamErr.message}`); - }); - - stream.on('close', () => { - console.log(`[INFO] Stats stream closed for container ${containerInfo.Id}`); - }); }); - }); + + statsStream.on('error', (err) => { + console.error(`[ERROR] Stats stream error for container ${containerInfo.Id}: ${err.message}`); + }); + + statsStream.on('close', () => { + console.log(`[INFO] Stats stream closed for container ${containerInfo.Id}`); + }); + } catch (err) { + console.error(`[ERROR] Failed to start stats stream for container ${containerInfo.Id}: ${err.message}`); + } + + return statsData; } +async function handleStatsBroadcast() { + const containerStats = {}; + + // Periodically update stats and broadcast + setInterval(async () => { + await collectContainerStats(containerStats); + const aggregatedStats = Object.values(containerStats); + const response = { type: 'allStats', data: aggregatedStats }; + + for (const peer of connectedPeers) { + peer.write(JSON.stringify(response)); + } + }, 1000); // Send stats every 500ms +} + +// Start the stats broadcast +handleStatsBroadcast(); + // Handle process termination