Container aus dem Proxmox-Template (neueste passende Version aus aplinfo), unprivilegiert, nesting automatisch für docker. Weil Proxmox keine Exec-API für Container hat, läuft die Provisionierung per SSH: bevorzugt pct exec über den Node, sonst direkt in den Container mit einem Bereitstellungsschlüssel, der am Ende wieder entfernt wird. Auf pve-demo beide Wege geprüft: Debian 13 mit docker per pct exec (hello-world läuft mit nesting allein) und Ubuntu 24.04 per SSH in den Container. Dabei gefunden: chrony scheitert ohne CAP_SYS_TIME (jetzt if: vm), sshd -t auf Ubuntu 24.04 ohne /run/sshd. Closes #009 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
80 lines
2.5 KiB
TypeScript
80 lines
2.5 KiB
TypeScript
import { phasenAusfuehren } from "@/engine/ablauf/ablauf";
|
||
import { sshBefehl } from "@/engine/ablaeufe/vm-ausrollen";
|
||
import { ProxmoxClient } from "@/engine/proxmox/client";
|
||
import { prisma } from "@/lib/db";
|
||
import { melden } from "@/server/ereignisse/senke";
|
||
import {
|
||
ausrollenVorbereiten,
|
||
ausrollSchritte,
|
||
kopfzeile,
|
||
type AusrollStand,
|
||
} from "@/server/services/ausrollen";
|
||
import { verbindungAus } from "@/server/services/server";
|
||
import { vmidReservieren } from "@/server/services/vmid";
|
||
import { ablaufRegistrieren } from "../ausfuehren";
|
||
import { aufrufLogger } from "../aufruf-log";
|
||
|
||
ablaufRegistrieren("AUSROLLEN", async ({ auftrag, senke, abbruchGewuenscht, angelegt }) => {
|
||
// Dieselbe Vorbereitung wie beim Anlegen – der Katalog könnte sich seitdem geändert haben.
|
||
const v = await ausrollenVorbereiten(auftrag.anfrage);
|
||
const stand: AusrollStand = {};
|
||
const kopfSetzen = async () => {
|
||
await prisma.auftrag.update({
|
||
where: { id: auftrag.id },
|
||
data: { kopf: kopfzeile(v, stand), knoten: stand.knoten ?? null },
|
||
});
|
||
await melden(auftrag.id);
|
||
};
|
||
await kopfSetzen();
|
||
|
||
const client = new ProxmoxClient(verbindungAus(v.server), { beobachter: aufrufLogger(senke) });
|
||
try {
|
||
const ergebnis = await phasenAusfuehren(
|
||
ausrollSchritte(
|
||
v,
|
||
{
|
||
client,
|
||
vmidReservieren: async (belegt, wunsch) => {
|
||
const vmid = await vmidReservieren({
|
||
serverId: v.server.id,
|
||
auftragId: auftrag.id,
|
||
belegt,
|
||
von: v.server.gastVmidVon,
|
||
wunsch,
|
||
});
|
||
await prisma.auftrag.update({ where: { id: auftrag.id }, data: { vmid } });
|
||
await kopfSetzen();
|
||
return vmid;
|
||
},
|
||
templateVmidReservieren: (belegt) =>
|
||
vmidReservieren({
|
||
serverId: v.server.id,
|
||
auftragId: auftrag.id,
|
||
belegt,
|
||
von: v.server.templateVmidVon,
|
||
bis: v.server.templateVmidBis,
|
||
}),
|
||
angelegt,
|
||
auftragKurzId: auftrag.kurzId,
|
||
},
|
||
stand,
|
||
),
|
||
senke,
|
||
{ abbruchGewuenscht },
|
||
);
|
||
await kopfSetzen();
|
||
if (!ergebnis.ok) return ergebnis;
|
||
return {
|
||
ok: true,
|
||
ergebnis: {
|
||
vmid: stand.vmid,
|
||
knoten: stand.knoten,
|
||
ip: stand.ip,
|
||
ssh: sshBefehl(v.anfrage.zugang.benutzer, stand.ip),
|
||
},
|
||
};
|
||
} finally {
|
||
await client.schliessen();
|
||
}
|
||
});
|