// src/lib/container-ops.ts — 容器操作(通过 SSH 执行 Docker 命令) import { execFileSync } from 'child_process' export type ContainerAction = 'restart' | 'stop' | 'start' | 'logs' export interface ContainerOpResult { success: boolean action: ContainerAction containerName: string output?: string error?: string } // 通过 SSH 在 txjp 服务器上执行 Docker 命令 function sshExec(cmd: string, timeoutMs = 15000): { stdout: string; stderr: string } { try { const result = execFileSync('ssh', ['txjp', cmd], { encoding: 'utf-8', timeout: timeoutMs, maxBuffer: 1024 * 1024, }) return { stdout: result.trim(), stderr: '' } } catch (err: unknown) { const e = err as { stderr?: Buffer; stdout?: Buffer; status?: number } return { stdout: e.stdout?.toString()?.trim() || '', stderr: e.stderr?.toString()?.trim() || String(err), } } } // 执行容器操作 export async function containerOp( containerName: string, action: ContainerAction, lines?: number, ): Promise { if (!containerName) { return { success: false, action, containerName: '', error: '容器名不能为空' } } let cmd: string switch (action) { case 'restart': cmd = `docker restart ${containerName}` break case 'stop': cmd = `docker stop ${containerName}` break case 'start': cmd = `docker start ${containerName}` break case 'logs': const n = Math.min(lines || 50, 200) cmd = `docker logs --tail ${n} ${containerName}` break default: return { success: false, action, containerName, error: '未知操作' } } try { const { stdout, stderr } = sshExec(cmd) if (stderr && !stdout) { return { success: false, action, containerName, error: stderr } } return { success: true, action, containerName, output: stdout || 'OK' } } catch (err) { return { success: false, action, containerName, error: String(err) } } } // 获取容器状态 export function getContainerStatus(containerName: string): string | null { try { const { stdout } = sshExec(`docker ps --format '{{.Status}}' -f name=^${containerName}$`) return stdout || null } catch { return null } }