feat(templates): Profile ins Template einbacken
Beim Template-Bau lassen sich Profile wählen (nur solche ohne Pflichtvariablen). Nach dem Vorbereitungsstart laufen sie über den Guest-Agent; danach werden Maschinen-ID, SSH-Host-Keys, Docker-Engine-ID und apt-Cache entfernt. Ausrollen nimmt das Template mit den meisten passenden Profilen und überspringt, was schon eingebacken ist. Auf pve-demo: Provisionierung mit base+docker 141 s ohne, ~30 s mit Template. Dabei gefunden: docker nimmt den Benutzer per guest.user in die Gruppe auf – Profile mit guest.* laufen deshalb beim Deploy noch einmal (idempotent, schnell). Closes #022 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -300,3 +300,63 @@ describe("Template-Bau", () => {
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Profile einbacken (#022)", () => {
|
||||
it("startet die VM, provisioniert über den Agent, räumt auf, fährt herunter – Name und Tags nennen die Profile", async () => {
|
||||
const { mock, client } = await aufbauen({ version: "9.2.1" });
|
||||
const dateien: string[] = [];
|
||||
let exec = 0;
|
||||
mock
|
||||
.route("POST", /\/agent\/ping$/, () => ({ data: { result: {} } }))
|
||||
.route("POST", /\/agent\/file-write$/, (a) => {
|
||||
dateien.push(Buffer.from(a.rumpf.get("content")!, "base64").toString("utf8"));
|
||||
return { data: null };
|
||||
})
|
||||
.route("POST", /\/agent\/exec$/, () => ({ data: { pid: ++exec } }))
|
||||
.route("GET", /\/agent\/exec-status$/, () => ({ data: { exited: 1, exitcode: 0 } }))
|
||||
.route("GET", /\/agent\/file-read$/, () => ({ data: { content: "" } }))
|
||||
.route("POST", /\/status\/shutdown$/, () => ({ data: UPID("qmshutdown") }));
|
||||
const katalog = await katalogLaden("catalog");
|
||||
const { profileAufloesen } = await import("@/engine/profile/aufloesen");
|
||||
const aufgeloest = profileAufloesen(
|
||||
["docker"],
|
||||
new Map(katalog.profile.map((p) => [p.eintrag.id, p.eintrag])),
|
||||
"debian",
|
||||
);
|
||||
if (!aufgeloest.ok) throw new Error("Profile");
|
||||
const ergebnis = await phasenAusfuehren(
|
||||
templateBauSchritte({
|
||||
client,
|
||||
distribution: await debian13(),
|
||||
profile: aufgeloest.profile,
|
||||
knoten: "pve01",
|
||||
storage: "local-zfs",
|
||||
bridge: "vmbr0",
|
||||
ssh: sshAufzeichnung().ssh,
|
||||
auftragKurzId: "t",
|
||||
holen: async () => `${HASH} debian-13-genericcloud-amd64.qcow2`,
|
||||
vmidReservieren: async () => 9002,
|
||||
warten: async () => {},
|
||||
}),
|
||||
stumm,
|
||||
);
|
||||
expect(ergebnis).toEqual({ ok: true });
|
||||
const anlegen = Object.fromEntries(
|
||||
mock.anfragen.find((a) => a.methode === "POST" && a.pfad === "/nodes/pve01/qemu")!.rumpf,
|
||||
);
|
||||
expect(anlegen).toMatchObject({
|
||||
name: "tpl-debian-13-docker",
|
||||
tags: "proxdeploy-template;debian-13;profil-base;profil-docker",
|
||||
});
|
||||
expect(dateien.join("")).toContain("docker-compose-plugin");
|
||||
expect(dateien.join("")).toContain("truncate -s 0 /etc/machine-id");
|
||||
expect(dateien.join("")).toContain("rm -f /etc/ssh/ssh_host_*");
|
||||
const reihenfolge = schreibend(mock.anfragen).filter((z) => /status\/(start|shutdown)|template$/.test(z));
|
||||
expect(reihenfolge).toEqual([
|
||||
"POST /nodes/pve01/qemu/9002/status/start",
|
||||
"POST /nodes/pve01/qemu/9002/status/start",
|
||||
"POST /nodes/pve01/qemu/9002/status/shutdown",
|
||||
"POST /nodes/pve01/qemu/9002/template",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user