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:
1 parent
8140c8cf80
commit
676e324381
2 files changed
+74
-6
No files matched your search
@@ -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;
|
||||||
Reference in new issue
Block a user