feat(api): API-Tokens, kurze Anfragen und OpenAPI für die CLI
- ApiToken (nur SHA-256), Bearer-Anmeldung, POST /auth/token für proxdeploy login, Verwaltung in den Einstellungen - anfrageErgaenzen: Storage, Bridge, Node, Benutzer und Schlüssel aus Server-Standards, Verbindungstest und Anmeldung – auch beim Template-Bau - Abschlussbox serverseitig (abschluss), Web und CLI zeigen dieselben Zeilen - Antwortschemas als zod, daraus /api/v1/openapi.json und cli/api/openapi.json (pnpm openapi) Refs #013 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
import { beforeEach, describe, expect, it } from "vitest";
|
||||
import { verschluesseln } from "@/lib/geheimnisse";
|
||||
import * as A from "@/lib/schemas/api";
|
||||
import { auftragAnlegen, auftragHolen } from "@/server/services/auftraege";
|
||||
import { distributionenListe, katalogSynchronisieren, profileListe } from "@/server/services/katalog";
|
||||
import { serverListe } from "@/server/services/server";
|
||||
import { datenbankLeeren, datenbankVerfuegbar, testPrisma } from "./helpers/db";
|
||||
import { angemeldet } from "./helpers/anfragen";
|
||||
|
||||
/** Die Antwortschemas (Quelle der Go-Typen) müssen zu dem passen, was die Services wirklich liefern. */
|
||||
describe.runIf(datenbankVerfuegbar)("Antwortschemas gegen echte Antworten", () => {
|
||||
beforeEach(async () => {
|
||||
await datenbankLeeren();
|
||||
await katalogSynchronisieren();
|
||||
});
|
||||
|
||||
it("Katalog, Server und Auftrag", async () => {
|
||||
for (const d of await distributionenListe({ nurAktive: true })) A.DistributionEintrag.parse(d);
|
||||
for (const p of await profileListe({ nurAktive: true })) A.ProfilEintrag.parse(p);
|
||||
|
||||
const server = await testPrisma.server.create({
|
||||
data: {
|
||||
name: "rz1",
|
||||
titel: "RZ 1",
|
||||
url: "https://127.0.0.1:8006",
|
||||
tokenId: "a@pve!b",
|
||||
tokenGeheimnis: verschluesseln("x"),
|
||||
fingerabdruck: "AA",
|
||||
},
|
||||
});
|
||||
for (const s of await serverListe()) A.ServerEintrag.parse(s);
|
||||
|
||||
const { benutzer } = await angemeldet("OPERATOR");
|
||||
const auftrag = await auftragAnlegen(
|
||||
{
|
||||
art: "AUSROLLEN",
|
||||
serverId: server.id,
|
||||
knoten: "pve01",
|
||||
gastTyp: "VM",
|
||||
distributionId: "debian-13",
|
||||
name: "web01",
|
||||
profile: ["base", "docker"],
|
||||
anfrage: {},
|
||||
},
|
||||
{ benutzer, quelle: "CLI" },
|
||||
null,
|
||||
async () => {},
|
||||
);
|
||||
A.AuftragSicht.parse(await auftragHolen(auftrag.kurzId));
|
||||
|
||||
await testPrisma.auftrag.update({
|
||||
where: { id: auftrag.id },
|
||||
data: {
|
||||
status: "ERFOLGREICH",
|
||||
vmid: 120,
|
||||
gestartetAm: new Date(Date.now() - 114_000),
|
||||
beendetAm: new Date(),
|
||||
ergebnis: { vmid: 120, knoten: "pve01", ip: "10.0.20.15", ssh: "ssh florian@10.0.20.15" },
|
||||
},
|
||||
});
|
||||
const fertig = A.AuftragSicht.parse(await auftragHolen(auftrag.kurzId));
|
||||
expect(fertig.abschluss).toEqual({
|
||||
ok: true,
|
||||
titel: "web01 bereit",
|
||||
dauer: "1m 54s",
|
||||
zeilen: [
|
||||
["VMID", "120"],
|
||||
["IP", "10.0.20.15"],
|
||||
["Profile", "base, docker"],
|
||||
["SSH", "ssh florian@10.0.20.15"],
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user