import { Client } from 'ssh2'; export interface SSHConnectionConfig { host: string; port?: number; username: string; privateKey?: string; password?: string; } export interface DockerContainer { name: string; image: string; status: string; ports: string[]; created: string; } export interface HostInfo { name: string; ip: string; online: boolean; containers: DockerContainer[]; cpuUsage?: number; memoryUsage?: number; uptime?: string; error?: string; } async function connectSSH(config: SSHConnectionConfig): Promise { return new Promise((resolve, reject) => { const conn = new Client(); conn.on('ready', () => resolve(conn)); conn.on('error', (err) => reject(err)); conn.connect({ host: config.host, port: config.port || 22, username: config.username, privateKey: config.privateKey, password: config.password, readyTimeout: 10000, }); }); } async function execSSH(conn: Client, command: string): Promise { return new Promise((resolve, reject) => { conn.exec(command, (err, stream) => { if (err) { reject(err); return; } let output = ''; stream.on('close', () => resolve(output)); stream.on('data', (data: Buffer) => { output += data.toString(); }); stream.stderr.on('data', (data: Buffer) => { output += data.toString(); }); }); }); } export async function discoverHostViaSSH( hostName: string, ip: string, sshConfig?: SSHConnectionConfig ): Promise { const defaultConfig: SSHConnectionConfig = { host: ip, username: 'bear', privateKey: require('fs').readFileSync(require('os').homedir() + '/.ssh/id_ed25519'), }; const config = sshConfig || defaultConfig; try { const conn = await connectSSH(config); const dockerPsCmd = `docker ps --format '{{.Names}}|{{.Image}}|{{.Status}}|{{.Ports}}|{{.CreatedAt}}'`; const dockerPsOutput = await execSSH(conn, dockerPsCmd); const containers: DockerContainer[] = dockerPsOutput .trim() .split('\n') .filter(line => line.trim()) .map(line => { const [name, image, status, ports, created] = line.split('|'); return { name: name.trim(), image: image.trim(), status: status.trim(), ports: ports.trim() ? ports.trim().split(', ') : [], created: created.trim(), }; }); conn.end(); return { name: hostName, ip: ip, online: true, containers, }; } catch (error: any) { return { name: hostName, ip: ip, online: false, containers: [], error: error.message || 'Connection failed', }; } } export async function discoverAllHostsSSH( hosts: { name: string; ip: string }[] ): Promise { const results = await Promise.all( hosts.map(host => discoverHostViaSSH(host.name, host.ip)) ); return results; } if (require.main === module) { const hosts = [ { name: 'ubuntu', ip: '192.168.50.61' }, { name: 'grizzley', ip: '192.168.50.84' }, { name: 'truenas', ip: '192.168.50.12' }, ]; discoverAllHostsSSH(hosts).then(results => { console.log(JSON.stringify(results, null, 2)); }).catch(console.error); }