monitor-ai/src/lib/container-ops.ts

81 lines
2.2 KiB
TypeScript

// 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<ContainerOpResult> {
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
}
}