/** * System Info * * Gathers system information including CPU, RAM, OS, and Docker status. */ import { exec } from 'node:child_process'; import { promisify } from 'node:util'; import * as os from 'node:os'; import type { ISystemInfo } from '../interfaces/gpu.ts'; import { GpuDetector } from './gpu-detector.ts'; import { logger } from '../logger.ts'; const execAsync = promisify(exec); /** * System Info class for gathering system information */ export class SystemInfo { private gpuDetector: GpuDetector; constructor() { this.gpuDetector = new GpuDetector(); } /** * Get complete system information */ public async getSystemInfo(): Promise { const [gpus, dockerVersion, nvidiaContainerVersion, kernelVersion] = await Promise.all([ this.gpuDetector.detectGpus(), this.getDockerVersion(), this.getNvidiaContainerVersion(), this.getKernelVersion(), ]); return { hostname: os.hostname(), cpuModel: this.getCpuModel(), cpuCores: os.cpus().length, ramTotal: Math.round(os.totalmem() / (1024 * 1024)), ramAvailable: Math.round(os.freemem() / (1024 * 1024)), os: this.getOsInfo(), kernelVersion, gpus, dockerVersion, nvidiaContainerVersion, }; } /** * Get CPU model name */ private getCpuModel(): string { const cpus = os.cpus(); if (cpus.length > 0) { return cpus[0].model; } return 'Unknown CPU'; } /** * Get OS information string */ private getOsInfo(): string { const platform = os.platform(); const release = os.release(); if (platform === 'linux') { return `Linux ${release}`; } else if (platform === 'darwin') { return `macOS ${release}`; } return `${platform} ${release}`; } /** * Get kernel version */ private async getKernelVersion(): Promise { try { const { stdout } = await execAsync('uname -r', { timeout: 5000 }); return stdout.trim(); } catch { return os.release(); } } /** * Get Docker version */ private async getDockerVersion(): Promise { try { const { stdout } = await execAsync('docker --version', { timeout: 5000 }); const match = stdout.match(/Docker version (\d+\.\d+\.\d+)/); return match ? match[1] : stdout.trim(); } catch { return undefined; } } /** * Get NVIDIA Container Toolkit version */ private async getNvidiaContainerVersion(): Promise { try { const { stdout } = await execAsync('nvidia-container-cli --version 2>&1 | head -1', { timeout: 5000 }); const match = stdout.match(/version (\d+\.\d+\.\d+)/); return match ? match[1] : undefined; } catch { return undefined; } } /** * Check if Docker is running */ public async isDockerRunning(): Promise { try { await execAsync('docker info', { timeout: 5000 }); return true; } catch { return false; } } /** * Check if NVIDIA Docker runtime is available */ public async isNvidiaRuntimeAvailable(): Promise { try { const { stdout } = await execAsync('docker info --format "{{.Runtimes}}"', { timeout: 5000 }); return stdout.includes('nvidia'); } catch { return false; } } /** * Check if Podman is available */ public async isPodmanAvailable(): Promise { try { await execAsync('podman --version', { timeout: 5000 }); return true; } catch { return false; } } /** * Get available disk space in the data directory * @param path Directory to check * @returns Available space in MB */ public async getAvailableDiskSpace(path: string = '/var/lib'): Promise { try { const { stdout } = await execAsync(`df -m "${path}" | tail -1 | awk '{print $4}'`, { timeout: 5000 }); return parseInt(stdout.trim(), 10) || 0; } catch { return 0; } } /** * Get system memory usage */ public getMemoryUsage(): { total: number; used: number; available: number; percent: number } { const total = Math.round(os.totalmem() / (1024 * 1024)); const available = Math.round(os.freemem() / (1024 * 1024)); const used = total - available; const percent = Math.round((used / total) * 100); return { total, used, available, percent }; } /** * Get system load average */ public getLoadAverage(): { load1: number; load5: number; load15: number } { const [load1, load5, load15] = os.loadavg(); return { load1: Math.round(load1 * 100) / 100, load5: Math.round(load5 * 100) / 100, load15: Math.round(load15 * 100) / 100, }; } /** * Print system info summary to logger */ public async printSystemInfo(): Promise { const info = await this.getSystemInfo(); logger.logBoxTitle('System Information', 70, 'info'); logger.logBoxLine(`Hostname: ${info.hostname}`); logger.logBoxLine(`OS: ${info.os}`); logger.logBoxLine(`Kernel: ${info.kernelVersion}`); logger.logBoxLine(`CPU: ${info.cpuModel} (${info.cpuCores} cores)`); logger.logBoxLine(`RAM: ${Math.round(info.ramTotal / 1024)} GB total, ${Math.round(info.ramAvailable / 1024)} GB available`); logger.logBoxLine(''); if (info.dockerVersion) { logger.logBoxLine(`Docker: v${info.dockerVersion}`); } else { logger.logBoxLine('Docker: Not installed'); } if (info.nvidiaContainerVersion) { logger.logBoxLine(`NVIDIA Container Toolkit: v${info.nvidiaContainerVersion}`); } logger.logBoxLine(''); logger.logBoxLine(`GPUs Detected: ${info.gpus.length}`); for (const gpu of info.gpus) { const vramGb = Math.round(gpu.vram / 1024 * 10) / 10; logger.logBoxLine(` ${gpu.id}: ${gpu.model} (${vramGb} GB)`); if (gpu.driverVersion) { logger.logBoxLine(` Driver: ${gpu.driverVersion}`); } if (gpu.cudaVersion) { logger.logBoxLine(` CUDA: ${gpu.cudaVersion}`); } if (gpu.rocmVersion) { logger.logBoxLine(` ROCm: ${gpu.rocmVersion}`); } } logger.logBoxEnd(); } }