Bereitstellungsvorlage: custom-Partitionierungsschema per API/GUI

CreateBereitstellungsvorlageRequest bekommt scheme + extra_partitions
(Mountpoint/Prozent/Dateisystem je Zusatzpartition), mit serverseitiger
Validierung (Prozentsumme < 100, keine doppelten Mountpoints, nur
ext4/btrfs). Bisher war "custom" laut Code-Kommentar nur per direkter
DB-Pflege erreichbar - jetzt vollstaendig ueber das bestehende Admin-
Formular (Organisationen -> Bereitstellungsvorlagen).

fetch_templates() liefert partitioning jetzt mit aus, damit die Admin-
Tabelle das gewaehlte Schema anzeigen kann.

Migration 0046 dokumentiert die neue JSONB-Form im Spalten-Default und
zieht bestehende Zeilen nach (Muster wie Migration 0026).

Teil der E2E-Testrunde, siehe platform-docs/roadmap/
e2e-testrunde-lokale-adressierung.md Phase 3. Gegenstueck im Install-
Backend (image_deploy_partition_custom() etc.) ist in tuxflotte-installer
bereits umgesetzt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DWKevK2QUK5tsGmqfSD6Yy
This commit is contained in:
adminandClaude Sonnet 5 committed 2026-09-19 14:52:13 +02:00
1 parent 8140c8cf80
commit 676e324381
2 files changed
+74 -6

No files matched your search

+44 -6
View File
@@ -244,6 +244,12 @@ class UpdateWebappTemplateRequest(BaseModel):
description: str | None = None description: str | None = None
class ExtraPartitionRequest(BaseModel):
mountpoint: str
percent: int
filesystem: str
class CreateBereitstellungsvorlageRequest(BaseModel): class CreateBereitstellungsvorlageRequest(BaseModel):
workspace_id: str workspace_id: str
backend_id: str backend_id: str
@@ -257,6 +263,12 @@ class CreateBereitstellungsvorlageRequest(BaseModel):
# _mint_image_detect_target_disk() und platform-docs/roadmap/ # _mint_image_detect_target_disk() und platform-docs/roadmap/
# multi-distro-merkmal-workspace-creator.md, Phase 0 (08.09.2026). # multi-distro-merkmal-workspace-creator.md, Phase 0 (08.09.2026).
target_disk_rank: int = 1 target_disk_rank: int = 1
# scheme:"custom" + extra_partitions (siehe platform-docs/roadmap/
# e2e-testrunde-lokale-adressierung.md Phase 3, 19.09.2026) - loest die
# bisherige Einschraenkung ab, dass ein custom-Schema nur per direkter
# DB-Pflege moeglich war (siehe Kommentar in create_bereitstellungsvorlage()).
scheme: str = "single"
extra_partitions: list[ExtraPartitionRequest] = []
class CreateEnrollmentSessionRequest(BaseModel): class CreateEnrollmentSessionRequest(BaseModel):
@@ -641,7 +653,8 @@ def fetch_templates(organization_id: str) -> list[dict]:
SELECT SELECT
bv.id, bv.label, bv.is_default, bv.id, bv.label, bv.is_default,
w.id, w.name, w.id, w.name,
b.id, b.name, b.version b.id, b.name, b.version,
bv.partitioning
FROM bereitstellungsvorlagen bv FROM bereitstellungsvorlagen bv
JOIN workspaces w ON w.id = bv.workspace_id JOIN workspaces w ON w.id = bv.workspace_id
JOIN backends b ON b.id = bv.backend_id JOIN backends b ON b.id = bv.backend_id
@@ -659,6 +672,7 @@ def fetch_templates(organization_id: str) -> list[dict]:
"workspace": {"id": str(row[3]), "name": row[4]}, "workspace": {"id": str(row[3]), "name": row[4]},
"backend": {"id": str(row[5]), "name": row[6], "version": row[7]}, "backend": {"id": str(row[5]), "name": row[6], "version": row[7]},
"is_default": row[2], "is_default": row[2],
"partitioning": row[8],
} }
for row in rows for row in rows
] ]
@@ -673,22 +687,25 @@ def create_bereitstellungsvorlage(
root_filesystem: str, root_filesystem: str,
secure_boot_required: bool, secure_boot_required: bool,
target_disk_rank: int = 1, target_disk_rank: int = 1,
scheme: str = "single",
extra_partitions: list[dict] | None = None,
) -> dict: ) -> dict:
""" """
Bislang gab es dafuer keinen API-/UI-Weg - Bereitstellungsvorlagen kamen Bislang gab es dafuer keinen API-/UI-Weg - Bereitstellungsvorlagen kamen
nur per Seed-Migration (0005/0011) fuer die "Default Lab"-Organisation nur per Seed-Migration (0005/0011) fuer die "Default Lab"-Organisation
zustande (siehe Phase 5 des Self-Service-ISO-Plans, dort als offene zustande (siehe Phase 5 des Self-Service-ISO-Plans, dort als offene
Luecke notiert). partitioning bekommt bewusst nur eine einfache Luecke notiert). Seit 19.09.2026 (siehe platform-docs/roadmap/
"root_filesystem"-Wahl im single-scheme (siehe Migration 0015 fuer die e2e-testrunde-lokale-adressierung.md Phase 3) deckt dieses Formular auch
volle Form) - ein custom-Schema mit extra_partitions ist Sache der scheme:"custom" + extra_partitions ab - Validierung liegt im aufrufenden
direkten DB-Pflege, nicht dieses Formulars. Endpoint (create_bereitstellungsvorlage_endpoint()).
""" """
vorlage_id = uuid4() vorlage_id = uuid4()
partitioning = { partitioning = {
"scheme": "single", "scheme": scheme,
"root_filesystem": root_filesystem, "root_filesystem": root_filesystem,
"target_disk_rank": target_disk_rank, "target_disk_rank": target_disk_rank,
"extra_partitions": extra_partitions or [],
} }
with get_database_connection() as conn: with get_database_connection() as conn:
@@ -4843,6 +4860,25 @@ def create_bereitstellungsvorlage_endpoint(
if payload.target_disk_rank < 1: if payload.target_disk_rank < 1:
return {"success": False, "error": "invalid_request", "message": "target_disk_rank muss mindestens 1 sein."} return {"success": False, "error": "invalid_request", "message": "target_disk_rank muss mindestens 1 sein."}
if payload.scheme not in ("single", "custom"):
return {"success": False, "error": "invalid_request", "message": "scheme muss 'single' oder 'custom' sein."}
if payload.scheme == "custom":
mountpoints = [p.mountpoint for p in payload.extra_partitions]
if len(mountpoints) != len(set(mountpoints)):
return {"success": False, "error": "invalid_request", "message": "extra_partitions enthält doppelte Mountpoints."}
if sum(p.percent for p in payload.extra_partitions) >= 100:
return {"success": False, "error": "invalid_request", "message": "Summe der extra_partitions-Prozente muss unter 100 bleiben."}
for p in payload.extra_partitions:
if not p.mountpoint.startswith("/"):
return {"success": False, "error": "invalid_request", "message": f"Mountpoint '{p.mountpoint}' muss mit '/' beginnen."}
if p.percent <= 0:
return {"success": False, "error": "invalid_request", "message": f"percent für '{p.mountpoint}' muss positiv sein."}
if p.filesystem not in ("ext4", "btrfs"):
return {"success": False, "error": "invalid_request", "message": f"Nicht unterstütztes Dateisystem für '{p.mountpoint}': {p.filesystem}"}
elif payload.extra_partitions:
return {"success": False, "error": "invalid_request", "message": "extra_partitions ist nur bei scheme='custom' erlaubt."}
vorlage = create_bereitstellungsvorlage( vorlage = create_bereitstellungsvorlage(
organization_id, organization_id,
payload.workspace_id, payload.workspace_id,
@@ -4853,6 +4889,8 @@ def create_bereitstellungsvorlage_endpoint(
payload.root_filesystem, payload.root_filesystem,
payload.secure_boot_required, payload.secure_boot_required,
payload.target_disk_rank, payload.target_disk_rank,
payload.scheme,
[p.model_dump() for p in payload.extra_partitions],
) )
return {"success": True, "bereitstellungsvorlage": vorlage} return {"success": True, "bereitstellungsvorlage": vorlage}
@@ -0,0 +1,30 @@
BEGIN;
-- Erweitert installation_directives.partitioning um scheme:"custom" (siehe
-- tuxflotte-installer Phase 3, image_deploy_partition_custom()): neben dem
-- bisherigen "single" kann jetzt eine Liste zusaetzlicher Partitionen
-- angegeben werden, z.B.
-- {"scheme": "custom", "root_filesystem": "ext4", "target_disk_rank": 1,
-- "extra_partitions": [{"mountpoint": "/home", "percent": 20, "filesystem": "ext4"},
-- {"mountpoint": "/var", "percent": 10, "filesystem": "btrfs"}]}
-- extra_partitions-Prozente sind Anteile der GESAMTEN Platte (nicht des
-- verbleibenden Rests nach Abzug der ESP), Summe muss < 100 bleiben (Rest
-- geht an root). filesystem aktuell nur ext4/btrfs (zfs/Fedora bewusst
-- nicht abgedeckt, siehe platform-docs/roadmap/
-- e2e-testrunde-lokale-adressierung.md Phase 3). Validiert wird sowohl im
-- Admin-Formular (kundenplattform/routers/admin_kunden.py) als auch
-- nochmal defensiv im Install-Backend (backend_validate() in
-- tuxflotte-installer/backends/*/backend.sh).
ALTER TABLE bereitstellungsvorlagen
ALTER COLUMN partitioning SET DEFAULT
'{"scheme": "single", "root_filesystem": "ext4", "target_disk_rank": 1, "extra_partitions": []}'::jsonb;
-- Bestehende Zeilen explizit nachziehen statt sich auf den Laufzeit-
-- Fallback "// []" im Backend zu verlassen - self-documenting statt
-- stillschweigend implizit (gleiches Muster wie Migration 0026 fuer
-- target_disk_rank).
UPDATE bereitstellungsvorlagen
SET partitioning = partitioning || '{"extra_partitions": []}'::jsonb
WHERE NOT (partitioning ? 'extra_partitions');
COMMIT;