feat: expand discovery with systemd services, LXC/VMs, SSH terminal, and filebrowser
- Add systemd service discovery to backend - Add Proxmox LXC/VM detection - Add hostType field to config for better host categorization - Fix SSH trust between hosts (ubuntu/grizzley -> truenas/proxmox) - Add SSH terminal support via xterm.js - Add filebrowser for browsing host filesystems - Update frontend types and components for new node types
This commit is contained in:
60
server/routes/terminal.ts
Normal file
60
server/routes/terminal.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { Router } from 'express';
|
||||
import { execSync } from 'child_process';
|
||||
import { homedir } from 'os';
|
||||
import { getHostConfigs } from '../config';
|
||||
|
||||
const router = Router();
|
||||
|
||||
interface TerminalRequest {
|
||||
host: string;
|
||||
command: string;
|
||||
}
|
||||
|
||||
router.post('/terminal/exec', async (req, res) => {
|
||||
try {
|
||||
const { host: hostName, command }: TerminalRequest = req.body;
|
||||
|
||||
if (!hostName || !command) {
|
||||
return res.status(400).json({ error: 'Missing host or command' });
|
||||
}
|
||||
|
||||
const hosts = getHostConfigs();
|
||||
const hostConfig = hosts.find(h => h.name === hostName);
|
||||
|
||||
if (!hostConfig) {
|
||||
return res.status(404).json({ error: `Host not found: ${hostName}` });
|
||||
}
|
||||
|
||||
const keyPath = (hostConfig.sshKeyPath || `${homedir()}/.ssh/id_ed25519`).replace(/^~/, homedir());
|
||||
const keyArg = `-i ${keyPath}`;
|
||||
const portArg = hostConfig.sshPort && hostConfig.sshPort !== 22 ? `-p ${hostConfig.sshPort}` : '';
|
||||
|
||||
const fullCommand = `ssh -o ConnectTimeout=10 -o StrictHostKeyChecking=no ${keyArg} ${portArg} ${hostConfig.sshUser}@${hostConfig.ip} ${command} 2>&1`;
|
||||
|
||||
const output = execSync(fullCommand, { encoding: 'utf-8', timeout: 30000 });
|
||||
|
||||
res.json({ output, error: null });
|
||||
} catch (error: any) {
|
||||
res.status(500).json({
|
||||
output: '',
|
||||
error: error.message || 'Command execution failed'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
router.get('/terminal/hosts', async (_req, res) => {
|
||||
try {
|
||||
const hosts = getHostConfigs();
|
||||
res.json({
|
||||
hosts: hosts.map(h => ({
|
||||
name: h.name,
|
||||
ip: h.ip,
|
||||
user: h.sshUser
|
||||
}))
|
||||
});
|
||||
} catch (error: any) {
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user