initial
This commit is contained in:
233
ts/hardware/system-info.ts
Normal file
233
ts/hardware/system-info.ts
Normal file
@@ -0,0 +1,233 @@
|
||||
/**
|
||||
* 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<ISystemInfo> {
|
||||
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<string> {
|
||||
try {
|
||||
const { stdout } = await execAsync('uname -r', { timeout: 5000 });
|
||||
return stdout.trim();
|
||||
} catch {
|
||||
return os.release();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Docker version
|
||||
*/
|
||||
private async getDockerVersion(): Promise<string | undefined> {
|
||||
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<string | undefined> {
|
||||
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<boolean> {
|
||||
try {
|
||||
await execAsync('docker info', { timeout: 5000 });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if NVIDIA Docker runtime is available
|
||||
*/
|
||||
public async isNvidiaRuntimeAvailable(): Promise<boolean> {
|
||||
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<boolean> {
|
||||
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<number> {
|
||||
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<void> {
|
||||
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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user