feat(auftraege): worker, Phasen und Live-Fortschritt per SSE
Aufträge laufen als pg-boss-Jobs im worker. Der Phasen-Runner der Engine kennt weder Proxmox noch Datenbank; eine Senke schreibt Phasen und Log in die DB und meldet per NOTIFY, die app streamt per SSE an Web und CLI (Last-Event-ID, Herzschlag, Polling-Fallback im Browser). VMIDs vergibt eine Advisory-Sperre je Server zusammen mit einer Reservierungstabelle; zehn parallele Reservierungen im Test bekommen zehn verschiedene IDs. Der Proxmox-Client hat einen Trockenmodus für den Dry-Run: Lesendes echt, Schreibendes nur aufgezeichnet. Live-Ansicht im Aufbau der CLI-Ausgabe. Im echten Betrieb aufgefallen: ssh2 und pg sind CommonJS und brauchen im worker Default-Importe. Closes #006 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "GastTyp" AS ENUM ('VM', 'LXC');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "AuftragsArt" AS ENUM ('AUSROLLEN', 'TEMPLATE_BAUEN', 'AUFRAEUMEN');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "AuftragsStatus" AS ENUM ('WARTEND', 'LAEUFT', 'ERFOLGREICH', 'FEHLGESCHLAGEN', 'ABGEBROCHEN', 'AUFGERAEUMT');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "PhasenStatus" AS ENUM ('OFFEN', 'LAEUFT', 'ERLEDIGT', 'FEHLER', 'UEBERSPRUNGEN');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Auftrag" (
|
||||
"id" TEXT NOT NULL,
|
||||
"kurzId" TEXT NOT NULL,
|
||||
"art" "AuftragsArt" NOT NULL,
|
||||
"status" "AuftragsStatus" NOT NULL DEFAULT 'WARTEND',
|
||||
"serverId" TEXT NOT NULL,
|
||||
"knoten" TEXT,
|
||||
"gastTyp" "GastTyp",
|
||||
"vmid" INTEGER,
|
||||
"name" TEXT,
|
||||
"distributionId" TEXT,
|
||||
"profile" TEXT[],
|
||||
"anfrage" JSONB NOT NULL,
|
||||
"plan" JSONB,
|
||||
"kopf" TEXT,
|
||||
"ergebnis" JSONB,
|
||||
"angelegt" JSONB,
|
||||
"fehler" JSONB,
|
||||
"quelle" "Quelle" NOT NULL,
|
||||
"erstelltVonId" TEXT NOT NULL,
|
||||
"wiederholtVonId" TEXT,
|
||||
"bezugId" TEXT,
|
||||
"abbrechen" BOOLEAN NOT NULL DEFAULT false,
|
||||
"erstelltAm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"gestartetAm" TIMESTAMP(3),
|
||||
"beendetAm" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "Auftrag_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Phase" (
|
||||
"id" TEXT NOT NULL,
|
||||
"auftragId" TEXT NOT NULL,
|
||||
"reihenfolge" INTEGER NOT NULL,
|
||||
"schluessel" TEXT NOT NULL,
|
||||
"titel" TEXT NOT NULL,
|
||||
"status" "PhasenStatus" NOT NULL DEFAULT 'OFFEN',
|
||||
"detail" TEXT,
|
||||
"ursache" TEXT,
|
||||
"hinweis" TEXT,
|
||||
"gestartetAm" TIMESTAMP(3),
|
||||
"beendetAm" TIMESTAMP(3),
|
||||
|
||||
CONSTRAINT "Phase_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Logeintrag" (
|
||||
"id" BIGSERIAL NOT NULL,
|
||||
"auftragId" TEXT NOT NULL,
|
||||
"zeit" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"stufe" TEXT NOT NULL,
|
||||
"phase" TEXT,
|
||||
"nachricht" TEXT NOT NULL,
|
||||
"daten" JSONB,
|
||||
|
||||
CONSTRAINT "Logeintrag_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "VmidReservierung" (
|
||||
"serverId" TEXT NOT NULL,
|
||||
"vmid" INTEGER NOT NULL,
|
||||
"auftragId" TEXT NOT NULL,
|
||||
"ablaufAm" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "VmidReservierung_pkey" PRIMARY KEY ("serverId","vmid")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Auftrag_kurzId_key" ON "Auftrag"("kurzId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Auftrag_serverId_erstelltAm_idx" ON "Auftrag"("serverId", "erstelltAm");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Auftrag_status_idx" ON "Auftrag"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Auftrag_erstelltAm_idx" ON "Auftrag"("erstelltAm");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Phase_auftragId_reihenfolge_idx" ON "Phase"("auftragId", "reihenfolge");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Phase_auftragId_schluessel_key" ON "Phase"("auftragId", "schluessel");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Logeintrag_auftragId_id_idx" ON "Logeintrag"("auftragId", "id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "VmidReservierung_auftragId_idx" ON "VmidReservierung"("auftragId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Auftrag" ADD CONSTRAINT "Auftrag_serverId_fkey" FOREIGN KEY ("serverId") REFERENCES "Server"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Auftrag" ADD CONSTRAINT "Auftrag_erstelltVonId_fkey" FOREIGN KEY ("erstelltVonId") REFERENCES "Benutzer"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Phase" ADD CONSTRAINT "Phase_auftragId_fkey" FOREIGN KEY ("auftragId") REFERENCES "Auftrag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Logeintrag" ADD CONSTRAINT "Logeintrag_auftragId_fkey" FOREIGN KEY ("auftragId") REFERENCES "Auftrag"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -0,0 +1,24 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "Template" (
|
||||
"id" TEXT NOT NULL,
|
||||
"serverId" TEXT NOT NULL,
|
||||
"knoten" TEXT NOT NULL,
|
||||
"vmid" INTEGER NOT NULL,
|
||||
"distributionId" TEXT NOT NULL,
|
||||
"storage" TEXT NOT NULL,
|
||||
"imageDatei" TEXT NOT NULL,
|
||||
"pruefsumme" TEXT NOT NULL,
|
||||
"gebautVonAuftragId" TEXT,
|
||||
"gebautAm" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "Template_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "Template_serverId_distributionId_idx" ON "Template"("serverId", "distributionId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Template_serverId_vmid_key" ON "Template"("serverId", "vmid");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Template" ADD CONSTRAINT "Template_serverId_fkey" FOREIGN KEY ("serverId") REFERENCES "Server"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
Reference in New Issue
Block a user