mirror of
https://github.com/khoaliber/dockhand.git
synced 2026-03-05 13:20:57 +00:00
74 lines
2.5 KiB
TypeScript
74 lines
2.5 KiB
TypeScript
import { json } from '@sveltejs/kit';
|
|
import type { RequestHandler } from './$types';
|
|
import { execInContainer, getContainerTop } from '$lib/server/docker';
|
|
import { authorize } from '$lib/server/authorize';
|
|
|
|
function parsePsOutput(output: string): { Titles: string[]; Processes: string[][] } | null {
|
|
const lines = output.trim().split('\n').filter(line => line.trim());
|
|
if (lines.length === 0) return null;
|
|
|
|
const headerLine = lines[0];
|
|
const headers = headerLine.trim().split(/\s+/);
|
|
|
|
// Find the index of COMMAND (last column, can have spaces)
|
|
const commandIndex = headers.findIndex(h => h === 'COMMAND' || h === 'CMD');
|
|
|
|
const processes = lines.slice(1).map(line => {
|
|
const parts = line.trim().split(/\s+/);
|
|
// COMMAND can have spaces, so join everything from commandIndex onwards
|
|
if (commandIndex !== -1 && parts.length > commandIndex) {
|
|
const beforeCommand = parts.slice(0, commandIndex);
|
|
const command = parts.slice(commandIndex).join(' ');
|
|
return [...beforeCommand, command];
|
|
}
|
|
return parts;
|
|
});
|
|
|
|
return { Titles: headers, Processes: processes };
|
|
}
|
|
|
|
export const GET: RequestHandler = async ({ params, url, cookies }) => {
|
|
const auth = await authorize(cookies);
|
|
|
|
const envId = url.searchParams.get('env');
|
|
const envIdNum = envId ? parseInt(envId) : undefined;
|
|
|
|
// Permission check with environment context (process list uses inspect permission)
|
|
if (auth.authEnabled && !await auth.can('containers', 'inspect', envIdNum)) {
|
|
return json({ error: 'Permission denied' }, { status: 403 });
|
|
}
|
|
|
|
try {
|
|
|
|
// Try different ps commands in order of preference
|
|
const psCommands = [
|
|
['ps', 'aux', '--sort=-pcpu'], // GNU ps with CPU sort
|
|
['ps', 'aux'], // GNU ps without sort
|
|
['ps', '-ef'], // POSIX ps
|
|
];
|
|
|
|
for (const cmd of psCommands) {
|
|
try {
|
|
const output = await execInContainer(params.id, cmd, envIdNum);
|
|
// Check if output looks like an error message (BusyBox error, etc.)
|
|
if (output.includes('unrecognized option') || output.includes('Usage:') || output.includes('BusyBox')) {
|
|
continue;
|
|
}
|
|
const result = parsePsOutput(output);
|
|
if (result && result.Processes.length > 0) {
|
|
return json({ ...result, source: 'ps' });
|
|
}
|
|
} catch {
|
|
// Try next command
|
|
}
|
|
}
|
|
|
|
// Fallback to docker top API
|
|
const top = await getContainerTop(params.id, envIdNum);
|
|
return json({ ...top, source: 'top' });
|
|
} catch (error: any) {
|
|
console.error('Failed to get container processes:', error);
|
|
return json({ error: error.message || 'Failed to get processes' }, { status: 500 });
|
|
}
|
|
};
|