import { beforeEach, describe, expect, it } from "vitest"; import * as liste from "@/app/api/v1/vorlagen/route"; import * as einzeln from "@/app/api/v1/vorlagen/[name]/route"; import { verschluesseln } from "@/lib/geheimnisse"; import { vorlageAnwenden } from "@/lib/schemas/vorlage"; import { ausrollenVorbereiten } from "@/server/services/ausrollen"; import { katalogSynchronisieren } from "@/server/services/katalog"; import { beispielVorlageAnlegen } from "@/server/services/vorlagen"; import { datenbankLeeren, datenbankVerfuegbar, testPrisma } from "./helpers/db"; import { angemeldet, anfrage, kontext } from "./helpers/anfragen"; const SCHLUESSEL = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEFTdkCuqQ6mF7I8QzmkNaQpKj7S/I2+yuxWeYasJjLd florian@test"; describe("Vorlage anwenden", () => { it("Anfrage gewinnt; netz und variablen werden feldweise gemischt, Listen ersetzt", () => { const ergebnis = vorlageAnwenden( { cores: 2, speicherMb: 4096, profile: ["base", "docker"], netz: { bridge: "vmbr1", vlan: 20 }, variablen: { "zabbix-agent": { server: "zbx" } }, }, { cores: 4, netz: { modus: "dhcp" }, profile: ["base"], variablen: { "zabbix-agent": { server_active: "zbx2" } }, name: undefined, }, ); expect(ergebnis).toEqual({ cores: 4, speicherMb: 4096, profile: ["base"], netz: { bridge: "vmbr1", vlan: 20, modus: "dhcp" }, variablen: { "zabbix-agent": { server: "zbx", server_active: "zbx2" } }, }); }); }); describe.runIf(datenbankVerfuegbar)("Vorlagen", () => { beforeEach(async () => { await datenbankLeeren(); await katalogSynchronisieren(); }); it("Beispiel „Docker-Host klein“ wird einmal angelegt und kommt nach dem Löschen nicht wieder", async () => { await beispielVorlageAnlegen(); expect( (await testPrisma.vorlage.findUniqueOrThrow({ where: { name: "docker-host-klein" } })).parameter, ).toMatchObject({ distribution: "debian-13", cores: 2, speicherMb: 4096, profile: ["base", "docker"], }); await testPrisma.vorlage.delete({ where: { name: "docker-host-klein" } }); await beispielVorlageAnlegen(); expect(await testPrisma.vorlage.count()).toBe(0); }); it("CRUD über die API; Operator darf pflegen; Name, IP und Schlüssel gehören nicht hinein", async () => { const operator = (await angemeldet("OPERATOR")).cookie; const neu = { name: "Web-Klein", titel: "Web klein", parameter: { typ: "vm", distribution: "debian-13", cores: 1 }, }; const angelegt = await liste.POST(anfrage("POST", "/api/v1/vorlagen", operator, neu)); expect(angelegt.status).toBe(201); expect((await angelegt.json()).name).toBe("web-klein"); expect((await liste.POST(anfrage("POST", "/api/v1/vorlagen", operator, neu))).status).toBe(409); const mitName = await liste.POST( anfrage("POST", "/api/v1/vorlagen", operator, { ...neu, name: "x", parameter: { name: "web01" } }), ); expect(mitName.status).toBe(400); const geaendert = await einzeln.PUT( anfrage("PUT", "/api/v1/vorlagen/web-klein", operator, { ...neu, titel: "Web, klein", parameter: { cores: 2 }, }), kontext({ name: "web-klein" }), ); expect((await geaendert.json()).parameter).toEqual({ cores: 2 }); expect( ( await einzeln.DELETE( anfrage("DELETE", "/api/v1/vorlagen/web-klein", operator), kontext({ name: "web-klein" }), ) ).status, ).toBe(204); expect(await testPrisma.protokoll.count({ where: { ziel: "vorlage:web-klein" } })).toBe(3); }); it("Ausrollen mit vorlage: Werte der Vorlage, Anfrage gewinnt, Name im CLI-Befehl", async () => { await beispielVorlageAnlegen(); 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", }, }); const v = await ausrollenVorbereiten({ vorlage: "docker-host-klein", server: "rz1", name: "web01", storage: "local-zfs", speicherMb: 8192, netz: { bridge: "vmbr0" }, zugang: { benutzer: "florian", sshSchluessel: [SCHLUESSEL] }, }); expect(v.anfrage).toMatchObject({ typ: "vm", distribution: "debian-13", cores: 2, speicherMb: 8192, diskGb: 40, vorlage: "docker-host-klein", }); expect(v.profile.map((p) => p.profil.id)).toEqual(["base", "docker"]); }); });