Compare commits
No commits in common. "eeb5879a466f5685a8714b4e416c7d2ee7341770" and "c0877548ec37d21b4cf236f88dd6c06224edd3e6" have entirely different histories.
eeb5879a46
...
c0877548ec
75
app.py
75
app.py
@ -8,7 +8,6 @@ import re
|
|||||||
import secrets
|
import secrets
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
import time
|
|
||||||
import unicodedata
|
import unicodedata
|
||||||
from uuid import UUID, uuid4
|
from uuid import UUID, uuid4
|
||||||
|
|
||||||
@ -47,19 +46,10 @@ MINT_ISO_PATH = str(Path(os.environ.get("TUXFLOTTE_MINT_ISO_PATH", "data/upstrea
|
|||||||
# zum eigenen Arbeitsverzeichnis.
|
# zum eigenen Arbeitsverzeichnis.
|
||||||
ISO_BUILD_OUTPUT_DIR = Path(os.environ.get("TUXFLOTTE_ISO_BUILD_OUTPUT_DIR", "data/iso-builds")).resolve()
|
ISO_BUILD_OUTPUT_DIR = Path(os.environ.get("TUXFLOTTE_ISO_BUILD_OUTPUT_DIR", "data/iso-builds")).resolve()
|
||||||
ISO_BUILD_TIMEOUT_SECONDS = 1800
|
ISO_BUILD_TIMEOUT_SECONDS = 1800
|
||||||
# ISO-Ablauf nach 7 Tagen (Migration 0021): ergaenzt die bestehende
|
|
||||||
# "neuer Build ersetzt alten"-Aufraeumung um eine reine Zeitdimension.
|
|
||||||
ISO_BUILD_EXPIRY_DAYS = 7
|
|
||||||
ISO_BUILD_EXPIRY_SWEEP_INTERVAL_SECONDS = 60 * 60
|
|
||||||
|
|
||||||
app = FastAPI(title="Provisioning Activation Server", version="0.1.0")
|
app = FastAPI(title="Provisioning Activation Server", version="0.1.0")
|
||||||
|
|
||||||
|
|
||||||
@app.on_event("startup")
|
|
||||||
def start_iso_build_expiry_sweep() -> None:
|
|
||||||
threading.Thread(target=run_iso_build_expiry_sweep, daemon=True).start()
|
|
||||||
|
|
||||||
|
|
||||||
class ActivationRequest(BaseModel):
|
class ActivationRequest(BaseModel):
|
||||||
activation_code: str
|
activation_code: str
|
||||||
device_fingerprint: str
|
device_fingerprint: str
|
||||||
@ -2086,7 +2076,7 @@ def recharge_enrollment_session(session_id: str, additional_devices: int, expire
|
|||||||
|
|
||||||
def iso_build_row_to_dict(row) -> dict:
|
def iso_build_row_to_dict(row) -> dict:
|
||||||
(build_id, organization_id, status, output_filename, error_message,
|
(build_id, organization_id, status, output_filename, error_message,
|
||||||
created_at, started_at, finished_at, expires_at) = row
|
created_at, started_at, finished_at) = row
|
||||||
return {
|
return {
|
||||||
"id": str(build_id),
|
"id": str(build_id),
|
||||||
"organization_id": str(organization_id),
|
"organization_id": str(organization_id),
|
||||||
@ -2096,7 +2086,6 @@ def iso_build_row_to_dict(row) -> dict:
|
|||||||
"created_at": created_at.isoformat(),
|
"created_at": created_at.isoformat(),
|
||||||
"started_at": started_at.isoformat() if started_at else None,
|
"started_at": started_at.isoformat() if started_at else None,
|
||||||
"finished_at": finished_at.isoformat() if finished_at else None,
|
"finished_at": finished_at.isoformat() if finished_at else None,
|
||||||
"expires_at": expires_at.isoformat() if expires_at else None,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
def fetch_iso_build(build_id: str):
|
def fetch_iso_build(build_id: str):
|
||||||
@ -2105,7 +2094,7 @@ def fetch_iso_build(build_id: str):
|
|||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
SELECT id, organization_id, status, output_filename, error_message,
|
SELECT id, organization_id, status, output_filename, error_message,
|
||||||
created_at, started_at, finished_at, expires_at
|
created_at, started_at, finished_at
|
||||||
FROM iso_builds
|
FROM iso_builds
|
||||||
WHERE id = %s
|
WHERE id = %s
|
||||||
""",
|
""",
|
||||||
@ -2120,7 +2109,7 @@ def fetch_iso_builds(organization_id: str):
|
|||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
SELECT id, organization_id, status, output_filename, error_message,
|
SELECT id, organization_id, status, output_filename, error_message,
|
||||||
created_at, started_at, finished_at, expires_at
|
created_at, started_at, finished_at
|
||||||
FROM iso_builds
|
FROM iso_builds
|
||||||
WHERE organization_id = %s
|
WHERE organization_id = %s
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
@ -2149,12 +2138,6 @@ def update_iso_build(
|
|||||||
mark_started: bool = False,
|
mark_started: bool = False,
|
||||||
mark_finished: bool = False,
|
mark_finished: bool = False,
|
||||||
):
|
):
|
||||||
# expires_at nur bei einem tatsaechlich erfolgreichen Abschluss setzen -
|
|
||||||
# ein "failed"-Build hat nichts zum Downloaden, das ablaufen koennte
|
|
||||||
# (dessen Zeile raeumt weiterhin ausschliesslich cleanup_old_iso_builds()
|
|
||||||
# beim naechsten Bau derselben Organisation auf).
|
|
||||||
setzt_expiry = mark_finished and status == "completed"
|
|
||||||
|
|
||||||
with get_database_connection() as conn:
|
with get_database_connection() as conn:
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
@ -2165,7 +2148,6 @@ def update_iso_build(
|
|||||||
error_message = %s
|
error_message = %s
|
||||||
{", started_at = CURRENT_TIMESTAMP" if mark_started else ""}
|
{", started_at = CURRENT_TIMESTAMP" if mark_started else ""}
|
||||||
{", finished_at = CURRENT_TIMESTAMP" if mark_finished else ""}
|
{", finished_at = CURRENT_TIMESTAMP" if mark_finished else ""}
|
||||||
{f", expires_at = CURRENT_TIMESTAMP + INTERVAL '{ISO_BUILD_EXPIRY_DAYS} days'" if setzt_expiry else ""}
|
|
||||||
WHERE id = %s
|
WHERE id = %s
|
||||||
""",
|
""",
|
||||||
(status, output_filename, error_message, build_id),
|
(status, output_filename, error_message, build_id),
|
||||||
@ -2204,57 +2186,6 @@ def cleanup_old_iso_builds(organization_id: str, keep_build_id) -> None:
|
|||||||
(organization_id, keep_build_id),
|
(organization_id, keep_build_id),
|
||||||
)
|
)
|
||||||
|
|
||||||
def cleanup_expired_iso_builds() -> int:
|
|
||||||
"""
|
|
||||||
Zeitbasierte Ergaenzung zu cleanup_old_iso_builds(): loescht Datei +
|
|
||||||
Zeile jedes abgeschlossenen Builds, dessen expires_at in der
|
|
||||||
Vergangenheit liegt - unabhaengig davon, ob die Organisation je erneut
|
|
||||||
baut (die bisherige Logik greift nur beim naechsten Bau derselben Org).
|
|
||||||
Laeuft periodisch ueber run_iso_build_expiry_sweep(). Gibt die Anzahl
|
|
||||||
geloeschter Builds zurueck (fuer Logging/Tests).
|
|
||||||
"""
|
|
||||||
|
|
||||||
with get_database_connection() as conn:
|
|
||||||
with conn.cursor() as cur:
|
|
||||||
cur.execute(
|
|
||||||
"""
|
|
||||||
SELECT id, output_filename FROM iso_builds
|
|
||||||
WHERE status = 'completed' AND expires_at IS NOT NULL AND expires_at < CURRENT_TIMESTAMP
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
abgelaufene_builds = cur.fetchall()
|
|
||||||
|
|
||||||
for build_id, output_filename in abgelaufene_builds:
|
|
||||||
if output_filename:
|
|
||||||
(ISO_BUILD_OUTPUT_DIR / output_filename).unlink(missing_ok=True)
|
|
||||||
|
|
||||||
cur.execute(
|
|
||||||
"""
|
|
||||||
DELETE FROM iso_builds
|
|
||||||
WHERE status = 'completed' AND expires_at IS NOT NULL AND expires_at < CURRENT_TIMESTAMP
|
|
||||||
"""
|
|
||||||
)
|
|
||||||
|
|
||||||
return len(abgelaufene_builds)
|
|
||||||
|
|
||||||
def run_iso_build_expiry_sweep() -> None:
|
|
||||||
"""
|
|
||||||
Endlosschleife in einem Daemon-Thread (siehe on_startup unten) - stuendlich
|
|
||||||
abgelaufene ISO-Builds raeumen. Ein Fehler in einem Durchlauf (z.B.
|
|
||||||
kurzzeitig nicht erreichbare DB) darf die Schleife nicht beenden, sonst
|
|
||||||
liefe der Sweep fuer den Rest der Prozesslaufzeit gar nicht mehr.
|
|
||||||
"""
|
|
||||||
|
|
||||||
while True:
|
|
||||||
time.sleep(ISO_BUILD_EXPIRY_SWEEP_INTERVAL_SECONDS)
|
|
||||||
|
|
||||||
try:
|
|
||||||
anzahl = cleanup_expired_iso_builds()
|
|
||||||
if anzahl:
|
|
||||||
print(f"[iso-build-expiry] {anzahl} abgelaufene(n) ISO-Build(s) geloescht.")
|
|
||||||
except Exception as exc:
|
|
||||||
print(f"[iso-build-expiry] Sweep-Fehler (naechster Versuch in {ISO_BUILD_EXPIRY_SWEEP_INTERVAL_SECONDS}s): {exc}")
|
|
||||||
|
|
||||||
def compute_iso_volid(organization_name: str) -> str:
|
def compute_iso_volid(organization_name: str) -> str:
|
||||||
"""
|
"""
|
||||||
ISO9660-Volume-ID fuer eine personalisierte Kunden-ISO: Organisationsname
|
ISO9660-Volume-ID fuer eine personalisierte Kunden-ISO: Organisationsname
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
-- ISO-Ablauf nach 7 Tagen (siehe ADR-Nachtrag zu ADR-0014). Ergaenzt die
|
|
||||||
-- bestehende "neuer Build ersetzt alten Build derselben Org"-Aufraeumung
|
|
||||||
-- (cleanup_old_iso_builds()) um eine reine Zeitdimension, die unabhaengig
|
|
||||||
-- davon greift, ob die Organisation je erneut baut.
|
|
||||||
ALTER TABLE iso_builds ADD COLUMN expires_at TIMESTAMPTZ;
|
|
||||||
Loading…
x
Reference in New Issue
Block a user