From 40d9bc77a6c47f4868a3d484428994e63ec1571a Mon Sep 17 00:00:00 2001 From: Thomas Stallinger Date: Tue, 14 Jul 2026 10:28:30 +0200 Subject: [PATCH] docs: document provisioning handshake and persistence model --- adr/0001-postgresql-platform-database.md | 61 ++++++ architecture/00-provisioning-flow.md | 51 +++++ architecture/05-runtime-blueprint.md | 66 ++++++ architecture/07-runtime-layout.md | 56 ++++++ architecture/08-provisioning-api.md | 142 +++++++++++++ architecture/09-data-model-v1.md | 246 +++++++++++++++++++++++ roadmap/installer-roadmap.md | 2 +- 7 files changed, 623 insertions(+), 1 deletion(-) create mode 100644 adr/0001-postgresql-platform-database.md create mode 100644 architecture/00-provisioning-flow.md create mode 100644 architecture/07-runtime-layout.md create mode 100644 architecture/08-provisioning-api.md create mode 100644 architecture/09-data-model-v1.md diff --git a/adr/0001-postgresql-platform-database.md b/adr/0001-postgresql-platform-database.md new file mode 100644 index 0000000..dbf7a11 --- /dev/null +++ b/adr/0001-postgresql-platform-database.md @@ -0,0 +1,61 @@ +# ADR-0001: PostgreSQL als persistente Plattformdatenbank + +**Status:** Beschlossen +**Datum:** 12.07.2026 + +## Kontext + +Tuxflotte verwaltet zunehmend persistente und miteinander verknüpfte Plattformdaten. + +Dazu gehören unter anderem: + +- Organisationen +- Geräte +- Gerätezuordnungen +- Hardware-Snapshots +- Netzwerkprofile +- Workspaces +- Backends +- Runtime Blueprints +- Secret-Referenzen + +Die bisherige dateibasierte Device Registry diente dem Nachweis des grundlegenden Provisioning-Handshakes. + +Für das langfristige Plattformmodell ist eine strukturierte persistente Datenhaltung erforderlich. + +## Entscheidung + +Tuxflotte verwendet PostgreSQL als persistente Plattformdatenbank. + +Die Datenbank bildet die Beziehungen zwischen Organisationen, Geräten, Hardware-Snapshots, Workspaces, Backends und Gerätezuordnungen ab. + +Die dateibasierte Device Registry wird nicht als dauerhaftes Persistenzmodell weitergeführt. + +Hardwareinformationen werden als zeitbezogene Snapshots gespeichert. + +Die stabile Geräteidentität und der erfasste Hardwarezustand werden getrennt behandelt. + +Secrets werden nicht als Klartextbestandteil der fachlichen Plattformdaten gespeichert. + +Das konkrete Secret-Management wird in einer separaten Architekturentscheidung definiert. + +## Konsequenzen + +Der Provisioning-Server erhält eine PostgreSQL-Anbindung. + +Änderungen am Datenbankschema werden über versionierte Migrationen verwaltet. + +Geräte erhalten eine interne, von Hardwaremerkmalen unabhängige Datenbank-ID. + +Der Hardware-Fingerprint dient der Wiedererkennung eines Geräts während des Provisioning-Handshakes. + +Hardwaredaten werden getrennt von der Geräteidentität als Snapshots gespeichert. + +Ein Gerät kann mehrere Hardware-Snapshots besitzen. + +Netzwerkinterfaces und Massenspeicher können einem Hardware-Snapshot zugeordnet werden. + +Die bestehende dateibasierte Device Registry wird nach erfolgreicher Einführung der Datenbank entfernt. + +Die Provisioning API bleibt von der konkreten Persistenzimplementierung unabhängig. + diff --git a/architecture/00-provisioning-flow.md b/architecture/00-provisioning-flow.md new file mode 100644 index 0000000..50a169d --- /dev/null +++ b/architecture/00-provisioning-flow.md @@ -0,0 +1,51 @@ +Boot + ↓ +Preflight + ↓ +Netzwerk + ↓ +Hardware Identity + ↓ +Server Discovery + ↓ +Device Registration + ↓ +Assignment + ↓ +Runtime Blueprint + ↓ +Backend Selection + ↓ +Backend API + ↓ +Native Installer + ↓ +First Boot + ↓ +Provisioning Agent + ↓ +Managed System + +## Aktivierung und Gerätebindung + +Ein neues Gerät authentifiziert den ersten Provisionierungsvorgang mit einem Aktivierungscode. + +Nach erfolgreicher Prüfung wird der vom Installer erzeugte Hardware-Fingerprint an den Provisioning-Server übertragen. + +Der Server bindet den Fingerprint an die Aktivierung beziehungsweise an die zugehörige Organisation. + +Der Aktivierungscode ist damit die initiale Berechtigung. + +Der Hardware-Fingerprint dient anschließend zur Wiedererkennung des Geräts. + +Ablauf: + +Aktivierungscode + ↓ +Hardware-Fingerprint + ↓ +Geräteregistrierung oder Wiedererkennung + ↓ +Profil- beziehungsweise Workspace-Zuordnung + ↓ +Runtime Blueprint diff --git a/architecture/05-runtime-blueprint.md b/architecture/05-runtime-blueprint.md index e69de29..0ca77ff 100644 --- a/architecture/05-runtime-blueprint.md +++ b/architecture/05-runtime-blueprint.md @@ -0,0 +1,66 @@ +# Runtime Blueprint Model + +**Status:** Stable + +## Zweck dieses Dokuments + +Dieses Dokument beschreibt das Runtime Blueprint als zentralen Integrationspunkt des Provisionierungsprozesses von Tuxflotte. + +Es definiert seine Aufgabe innerhalb der Plattform und beschreibt seine Verantwortung sowie seine Abgrenzung zu den übrigen Komponenten der Architektur. + +--- + +## Motivation + +Workspace, Organization und Backend beschreiben jeweils einen eigenständigen Aspekt einer Bereitstellung. + +Erst durch ihr Zusammenführen entsteht die vollständige Beschreibung einer konkreten Bereitstellung. + +Das Runtime Blueprint verbindet diese Informationen und bildet die Grundlage für den weiteren Provisionierungsprozess. + +--- + +## Definition + +Das Runtime Blueprint beschreibt den vollständigen Zielzustand einer konkreten Bereitstellung. + +Es wird zentral aus den Informationen von Workspace, Organization und Backend erzeugt und bereitgestellt. + +Jede Bereitstellung erhält ihr eigenes Runtime Blueprint. + +--- + +## Provisionierungsprozess + +Der Provisionierungsprozess beginnt mit der Auswahl eines Workspace und endet nicht mit der Installation des Betriebssystems. + +Er beschreibt den Weg von der fachlichen Beschreibung eines Arbeitsplatzes bis zur Umsetzung des gewünschten Zielzustands. + +Während dieses Prozesses wird das Runtime Blueprint zentral erzeugt und den ausführenden Komponenten der Plattform bereitgestellt. + +Der Installer setzt den beschriebenen Zielzustand während der Erstbereitstellung um. + +Nach der Registrierung setzt der Provisioning Agent Änderungen des Zielzustands im weiteren Lebenszyklus um. + +--- + +## Verantwortungsbereich + +Das Runtime Blueprint beschreibt insbesondere + +den vollständigen Zielzustand einer konkreten Bereitstellung, +die Zusammenführung der Informationen aus Workspace, Organization und Backend, +alle für die Umsetzung erforderlichen Informationen sowie +die Grundlage für die Umsetzung durch Installer und Provisionierungs-Agent. + +Das Runtime Blueprint beschreibt den Zielzustand. + +Die Umsetzung dieses Zielzustands erfolgt durch die ausführenden Komponenten der Plattform. + +--- + +## Zusammenfassung + +Das Runtime Blueprint verbindet die fachlichen Modelle von Tuxflotte mit ihrer konkreten Umsetzung. + +Es bildet den zentralen Integrationspunkt des Provisionierungsprozesses und beschreibt den vollständigen Zielzustand eines konkreten Systems. diff --git a/architecture/07-runtime-layout.md b/architecture/07-runtime-layout.md new file mode 100644 index 0000000..792b9a2 --- /dev/null +++ b/architecture/07-runtime-layout.md @@ -0,0 +1,56 @@ +# Runtime Layout + +## Laufzeitverzeichnis + +Alle Installer-Module kommunizieren ausschließlich über: + +/run/tuxflotte/ + +Jedes Modul besitzt genau ein eigenes Unterverzeichnis. + +## Verzeichnisstruktur + +/run/tuxflotte/ +├── network/ +├── hardware/ +├── server/ +├── runtime/ +├── backend/ +└── logs/ + +## Eigentümer der Verzeichnisse + +network/ +Besitzer: 05_network.sh + +hardware/ +Besitzer: 10_hardware.sh + +server/ +Besitzer: 15_server_handshake.sh + +runtime/ +Besitzer: Runtime-Builder + +backend/ +Besitzer: Backend-Orchestrator + +logs/ +Besitzer: zentraler Installer-Orchestrator + +## Lese- und Schreibregeln + +Ein Modul darf ausschließlich in sein eigenes Verzeichnis schreiben. + +Andere Modulverzeichnisse dürfen nur gelesen werden, wenn dies für den definierten Ablauf erforderlich ist. + +Beispiele: + +- 10_hardware.sh schreibt nur nach /run/tuxflotte/hardware/ +- 15_server_handshake.sh liest aus /run/tuxflotte/network/ und /run/tuxflotte/hardware/ +- Der Runtime-Builder liest aus /run/tuxflotte/server/ +- Der Backend-Orchestrator liest aus /run/tuxflotte/runtime/ + +Direkte Funktionsaufrufe zwischen Modulen sind nicht vorgesehen. + +Die Kommunikation erfolgt ausschließlich über Dateien im Runtime-Verzeichnis. diff --git a/architecture/08-provisioning-api.md b/architecture/08-provisioning-api.md new file mode 100644 index 0000000..699c3d3 --- /dev/null +++ b/architecture/08-provisioning-api.md @@ -0,0 +1,142 @@ +# Provisioning API + +## Zweck + +Die Provisioning API beschreibt die Kommunikation zwischen dem Tuxflotte-Installer und dem Provisioning-Server. + +Sie ist distributionsunabhängig. + +Die Backend API (06-backend-api.md) beginnt erst nach der Erstellung des Runtime Blueprints. + +## Aktivierung + +### Endpoint + +POST /api/v1/activate + +### Zweck + +Der Endpoint autorisiert einen initialen Provisionierungsvorgang und registriert oder erkennt ein Gerät anhand seines Hardware-Fingerprints wieder. + +### Request + +```json +{ + "activation_code": "LAB-2026-START", + "device_fingerprint": "", + "hostname": "enterprise", + "machine_id": "", + "client_version": "0.1.0", + "hardware": { + "schema_version": 1, + "identity": { + "device_fingerprint": "", + "system_uuid": "", + "system_serial": null, + "board_serial": "", + "machine_id": "" + }, + "system": { + "manufacturer": null, + "product_name": null, + "product_version": null, + "architecture": "x86_64", + "cpu": { + "model": "", + "logical_count": 8 + }, + "memory_bytes": 33446432768 + }, + "mainboard": { + "vendor": "Intel Corporation", + "name": "DH87MC" + }, + "firmware": { + "bios_vendor": "Intel Corp.", + "bios_version": "", + "boot_mode": "bios", + "secure_boot": "unsupported" + }, + "security": { + "tpm_version": "none" + }, + "network_interfaces": [ + { + "name": "eno1", + "type": "ethernet", + "mac": "" + } + ], + "storage_devices": [ + { + "name": "sda", + "model": "", + "serial": "", + "size_bytes": 512110190592, + "transport": "sata" + } + ] + } +} + +Der `hardware`-Block enthält den während der Provisionierung erfassten Hardwarezustand. + +Der Provisioning-Server registriert oder erkennt das Gerät anhand des `device_fingerprint` und speichert den übertragenen Hardwarezustand als zeitbezogenen Hardware-Snapshot. + +Bei einer erneuten erfolgreichen Aktivierung desselben Geräts bleibt die interne Geräte-ID erhalten. Für den aktuellen Aktivierungsvorgang wird ein neuer Hardware-Snapshot erzeugt. + +### Response + +Bei erfolgreicher Aktivierung antwortet der Provisioning-Server mit dem registrierten Gerät, der zugeordneten Organisation und den verfügbaren Provisioning-Profilen. + +```json +{ + "success": true, + "device": { + "id": "", + "fingerprint": "", + "hostname": "enterprise", + "created": false, + "hardware_snapshot_id": "" + }, + "customer": { + "id": "default", + "organization_id": "", + "name": "Default Lab" + }, + "profiles": [ + { + "id": "fedora-workstation", + "label": "Fedora Workstation", + "distribution": "fedora", + "version": "40", + "description": "Standard-Workstation-Profil für Fedora.", + "ansible_repo": "", + "installer": { + "type": "kickstart", + "url": "" + } + } + ] +} +``` + +`device.id` ist die interne, von Hardwaremerkmalen unabhängige Geräte-ID. + +`device.created` gibt an, ob das Gerät während dieses Aktivierungsvorgangs neu registriert wurde. + +`device.hardware_snapshot_id` referenziert den für diesen Aktivierungsvorgang erzeugten Hardware-Snapshot. + +Der Aktivierungscode bestimmt die zugeordnete Organisation und die für den Provisionierungsvorgang verfügbaren Profile. + +### Fehlerantwort + +Ist der Aktivierungscode ungültig, antwortet der Provisioning-Server mit: + +```json +{ + "success": false, + "error": "invalid_activation_code", + "message": "Der Aktivierungscode ist ungültig." +} +``` diff --git a/architecture/09-data-model-v1.md b/architecture/09-data-model-v1.md new file mode 100644 index 0000000..87c8e4a --- /dev/null +++ b/architecture/09-data-model-v1.md @@ -0,0 +1,246 @@ +# Tuxflotte Datenmodell v1 + +## Zweck + +Das Datenmodell beschreibt die persistenten Kernobjekte der Tuxflotte-Plattform und ihre Beziehungen. + +Die konkrete SQL-Implementierung und das Migrationssystem werden getrennt von diesem fachlichen Modell behandelt. + +## Kernobjekte + +- Organization +- Device +- Hardware Snapshot +- Network Interface +- Storage Device +- Workspace +- Backend +- Assignment +- Network Profile +- Secret Reference + +## Organization + +Eine Organization beschreibt eine organisatorische Einheit innerhalb der Tuxflotte-Plattform. + +Eine Organization besitzt eigene Geräte, Workspaces, Netzwerkprofile und Richtlinien. + +Attribute: + +- id +- name +- created_at +- updated_at + +Beziehungen: + +- besitzt mehrere Devices +- besitzt mehrere Workspaces +- besitzt mehrere Network Profiles +- referenziert Secrets + +## Device + +Ein Device repräsentiert ein dauerhaft bekanntes physisches oder virtuelles Gerät. + +Die interne Geräte-ID ist unabhängig von Hardwaremerkmalen. + +Der Hardware-Fingerprint dient der Wiedererkennung während des Provisioning-Handshakes. + +Attribute: + +- id +- organization_id +- device_fingerprint +- hostname +- created_at +- last_seen + +Beziehungen: + +- gehört zu genau einer Organization +- besitzt mehrere Hardware Snapshots +- besitzt optional ein Assignment + +## Hardware Snapshot + +Ein Hardware Snapshot beschreibt den zu einem bestimmten Zeitpunkt erfassten Hardwarezustand eines Devices. + +Hardware Snapshots sind zeitbezogene Inventardaten und nicht Bestandteil der stabilen Geräteidentität. + +Attribute: + +- id +- device_id +- collected_at +- architecture +- manufacturer +- product_name +- product_version +- system_uuid +- system_serial +- board_vendor +- board_name +- board_serial +- bios_vendor +- bios_version +- boot_mode +- secure_boot +- tpm_version +- cpu_model +- cpu_logical_count +- memory_bytes + +Beziehungen: + +- gehört zu genau einem Device +- besitzt mehrere Network Interfaces +- besitzt mehrere Storage Devices + +## Network Interface + +Ein Network Interface beschreibt eine zum Zeitpunkt des Hardware Snapshots vorhandene Netzwerkschnittstelle. + +Attribute: + +- id +- hardware_snapshot_id +- name +- type +- mac_address + +Beziehungen: + +- gehört zu genau einem Hardware Snapshot + +## Storage Device + +Ein Storage Device beschreibt einen zum Zeitpunkt des Hardware Snapshots vorhandenen Massenspeicher. + +Attribute: + +- id +- hardware_snapshot_id +- model +- serial +- size_bytes +- transport +- name + +Beziehungen: + +- gehört zu genau einem Hardware Snapshot + +## Relationales Schema v1 + +### organizations + +Spalten: + +- id +- name +- created_at +- updated_at + +### devices + +Spalten: + +- id +- organization_id +- device_fingerprint +- hostname +- created_at +- last_seen + +Beziehungen: + +- organization_id referenziert organizations.id + +Constraints: + +- device_fingerprint ist eindeutig + +### hardware_snapshots + +Spalten: + +- id +- device_id +- collected_at +- architecture +- manufacturer +- product_name +- product_version +- system_uuid +- system_serial +- board_vendor +- board_name +- board_serial +- bios_vendor +- bios_version +- boot_mode +- secure_boot +- tpm_version +- cpu_model +- cpu_logical_count +- memory_bytes + +Beziehungen: + +- device_id referenziert devices.id + +### network_interfaces + +Spalten: + +- id +- hardware_snapshot_id +- name +- type +- mac_address + +Beziehungen: + +- hardware_snapshot_id referenziert hardware_snapshots.id + +### storage_devices + +Spalten: + +- id +- hardware_snapshot_id +- name +- model +- serial +- size_bytes +- transport + +Beziehungen: + +- hardware_snapshot_id referenziert hardware_snapshots.id + +## Beziehungskonsequenzen + +Wird eine Organization gelöscht, dürfen zugehörige Devices nicht implizit mitgelöscht werden. + +Wird ein Device gelöscht, werden zugehörige Hardware Snapshots mitgelöscht. + +Wird ein Hardware Snapshot gelöscht, werden zugehörige Network Interfaces und Storage Devices automatisch mitgelöscht. + +Für die relationale Umsetzung gilt daher: + +- devices.organization_id → ON DELETE RESTRICT +- hardware_snapshots.device_id → ON DELETE CASCADE +- network_interfaces.hardware_snapshot_id → ON DELETE CASCADE +- storage_devices.hardware_snapshot_id → ON DELETE CASCADE + +## ID-Erzeugung + +Persistente Plattformobjekte verwenden UUIDs als interne IDs. + +UUIDs werden durch die Anwendung erzeugt. + +Die Datenbank validiert und speichert die IDs, erzeugt sie jedoch nicht selbst. + +Dadurch stehen Objekt-IDs bereits vor dem Datenbank-INSERT zur Verfügung und können innerhalb einer Transaktion für abhängige Datensätze verwendet werden. diff --git a/roadmap/installer-roadmap.md b/roadmap/installer-roadmap.md index 69ab065..38c4af6 100644 --- a/roadmap/installer-roadmap.md +++ b/roadmap/installer-roadmap.md @@ -39,7 +39,7 @@ Ziel: Netzwerkgestützter Installer. ### Registrierung -* [ ] Geräteaktivierung +* [x] Geräteaktivierung * [ ] Benutzeranmeldung * [ ] Auswahl von OS- und Konfigurationsprofilen