Eine VM aus dem ProxDeploy-Template ausrollen, vollständig per API: Klonen, Hardware, cloud-init, Start, Guest-Agent und Provisionierung der Profile über den Agent – ohne SSH. Der Fortschritt kommt aus der Logdatei im Gast, je Profil eine Marke. Der Dry-Run läuft durch dieselben Phasen mit einem Trocken-Client und zeigt jeden geplanten Proxmox-Aufruf und den passenden CLI-Befehl. Der Assistent hat 9 Schritte, den Zustand in der URL und bietet an, ein fehlendes Template im selben Auftrag zu bauen. Auf pve-demo abgenommen: pd-test01 (base, docker) per API, pd-test02 (base, zabbix-agent) über den Assistenten, beide per SSH geprüft. Dabei gefunden: file-write scheitert an Umlauten – Skripte gehen jetzt base64-kodiert hinüber. Closes #008 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
70 lines
2.2 KiB
TypeScript
70 lines
2.2 KiB
TypeScript
import { NextResponse } from "next/server";
|
||
import { ZodError } from "@/lib/validierung";
|
||
import { logger } from "@/lib/logger";
|
||
import { AnwendungsFehler } from "@/server/fehler";
|
||
|
||
/**
|
||
* Einheitliche Fehlerantwort der REST-API – Web-GUI und CLI lesen dasselbe Format:
|
||
* `{ fehler: { code, nachricht, hinweis?, felder? } }`.
|
||
*/
|
||
export type FehlerAntwort = {
|
||
fehler: { code: string; nachricht: string; hinweis?: string; felder?: Record<string, string> };
|
||
};
|
||
|
||
export function fehlerAntwort(fehler: unknown): NextResponse<FehlerAntwort> {
|
||
if (fehler instanceof AnwendungsFehler) {
|
||
return NextResponse.json(
|
||
{
|
||
fehler: {
|
||
code: fehler.code,
|
||
nachricht: fehler.message,
|
||
...(fehler.hinweis ? { hinweis: fehler.hinweis } : {}),
|
||
...(fehler.felder ? { felder: fehler.felder } : {}),
|
||
},
|
||
},
|
||
{ status: fehler.status },
|
||
);
|
||
}
|
||
if (fehler instanceof ZodError) {
|
||
const felder: Record<string, string> = {};
|
||
for (const problem of fehler.issues) {
|
||
const pfad = problem.path.join(".") || "_";
|
||
felder[pfad] ??= problem.message;
|
||
}
|
||
return NextResponse.json(
|
||
{
|
||
fehler: {
|
||
code: "ungueltig",
|
||
nachricht: "Die Eingaben sind nicht vollständig oder ungültig.",
|
||
felder,
|
||
},
|
||
},
|
||
{ status: 400 },
|
||
);
|
||
}
|
||
logger.error({ err: fehler }, "Unerwarteter Fehler in der API");
|
||
return NextResponse.json({ fehler: { code: "intern", nachricht: "Interner Fehler." } }, { status: 500 });
|
||
}
|
||
|
||
/** Umhüllt einen Route Handler: wandelt geworfene Fehler in das einheitliche Format. */
|
||
export function api<A extends unknown[]>(
|
||
handler: (...argumente: A) => Promise<Response>,
|
||
): (...argumente: A) => Promise<Response> {
|
||
return async (...argumente: A) => {
|
||
try {
|
||
return await handler(...argumente);
|
||
} catch (fehler) {
|
||
return fehlerAntwort(fehler);
|
||
}
|
||
};
|
||
}
|
||
|
||
/** Liest einen JSON-Rumpf; ein kaputter Rumpf ist ein 400, kein 500. */
|
||
export async function jsonLesen(anfrage: Request): Promise<unknown> {
|
||
try {
|
||
return await anfrage.json();
|
||
} catch {
|
||
throw new AnwendungsFehler(400, "kein_json", "Der Anfragerumpf ist kein gültiges JSON.");
|
||
}
|
||
}
|