feat(ui): add type filter toggles
This commit is contained in:
133
src/services/sshDiscovery.ts
Normal file
133
src/services/sshDiscovery.ts
Normal file
@@ -0,0 +1,133 @@
|
||||
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<Client> {
|
||||
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<string> {
|
||||
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<HostInfo> {
|
||||
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<HostInfo[]> {
|
||||
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);
|
||||
}
|
||||
Reference in New Issue
Block a user