# Kestra Scripts Dieses Repository enthält Kestra-Flows und Hilfsskripte für Homelab-Automatisierung. Aktuell enthalten: * `docker_stack_inventory_scan.yaml` * `build_select_options.py` * `linux_apt-upgrade.yaml` * `hetzner-vm-provision.yaml` * `hetzner-server-type-location-update.yaml` * `hetzner-server-available-list.yaml` * `hetzner-vm-destroy.yaml` * `.env.example` Der erste Flow scannt mehrere Docker-Hosts per SSH, sucht nach Docker-Compose-Stacks und schreibt daraus eine Dropdown-Liste in den Kestra KV-Store. --- ## Zweck Dieses Repository trennt bewusst: * **Kestra-Flow**: Ablaufsteuerung und Orchestrierung * **Python-Script**: Verarbeitung der Scan-Ergebnisse * **Secrets / Zugangsdaten**: außerhalb des Repositories über `.env` bzw. Kestra Secrets Damit bleibt der Flow übersichtlich, wartbar und sicherer. --- ## Dateien ### `docker_stack_inventory_scan.yaml` Kestra-Flow zum Scannen mehrerer Docker-Hosts. Der Flow: 1. verbindet sich per SSH mit definierten Docker-Hosts 2. durchsucht dort ein Basisverzeichnis nach Compose-Dateien 3. sammelt gefundene Docker-Stacks ein 4. übergibt die Ergebnisse an ein Python-Script 5. schreibt die fertige Dropdown-Liste in den Kestra KV-Store Gesucht werden unter anderem: ```text compose.yml compose.yaml docker-compose.yml docker-compose.yaml ``` --- ### `build_select_options.py` Python-Script zum Zusammenführen der Scan-Ergebnisse. Das Script liest die Umgebungsvariable: ```text OPTIONS_B64_JSON ``` Darin erwartet es eine JSON-Liste mit Base64-codierten Host-Ergebnissen. Ausgabe: ```text select_options.json ``` Diese Datei wird anschließend vom Kestra-Flow in den KV-Store geschrieben. --- ### `linux_apt-upgrade.yaml` Kestra-Flow zum Ausführen von `apt update && apt upgrade` auf einem Linux-Server per SSH. Der Flow: 1. verbindet sich per SSH mit dem Zielserver 2. erkennt automatisch ob der Benutzer root ist oder sudo benötigt 3. führt `apt-get update` und `apt-get upgrade` aus 4. meldet ob ein Reboot erforderlich ist Der Flow wird manuell gestartet und erwartet folgende Eingaben: | Input | Beschreibung | |---|---| | `host` | Server IP oder Hostname | | `user` | SSH-Benutzer | | `sudo_password` | Sudo-Passwort (Kestra Secret) | Benötigtes Kestra Secret: ```text SSH_PRIVATE_KEY ``` ![linux-apt-upgrade Flow](screenshots/linux_apt_upgrade.png) --- ### `hetzner-vm-provision.yaml` Kestra-Flow zum Provisionieren einer Hetzner Cloud VM via Terraform — mit KI-gestützter Plan-Analyse und manuellem Approval-Gate. **Namespace:** `hetzner` Der Flow läuft in vier Phasen: 1. **Terraform Plan** — erstellt einen Plan für die neue VM (Ubuntu 24.04) im Hetzner-Datacenter; Terraform State wird im S3-Backend (Hetzner Object Storage) gespeichert 2. **LLM-Analyse** — GPT-4o-mini fasst den Plan auf Deutsch zusammen und bewertet ob er sicher aussieht 3. **Approval-Gate** — Kestra pausiert und wartet auf manuelle Freigabe 4. **Terraform Apply / Abbruch** — bei Freigabe wird die VM erstellt und die IPv4-Adresse ausgegeben; bei Ablehnung wird die Execution abgebrochen Der Flow erwartet folgende Eingaben: | Input | Typ | Beschreibung | |---|---|---| | `vm_name` | STRING | Eindeutiger VM-Name, z.B. `dev-server-01` | | `server_type` | SELECT | `cx23` (2 vCPU / 4 GB) · `cx33` · `cx43` · `cx53` | | `location` | SELECT | `nbg1` · `fsn1` · `hel1` | | `team` | STRING | Label für die VM | Benötigte Kestra Secrets: ```text HCLOUD_TOKEN SSH_KEY_NAME AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY TF_BACKEND_BUCKET TF_BACKEND_ENDPOINT OPENAI_API_KEY ``` --- ### `hetzner-server-type-location-update.yaml` Kestra-Flow zum automatischen Aktualisieren der verfügbaren Hetzner Server-Typen und Standorte. **Namespace:** `hetzner` **Trigger:** Alle 15 Minuten, täglich 07:00–21:00 Uhr (Europe/Berlin) Der Flow: 1. **Hetzner API abfragen** — ruft die aktuellen Server-Typen (`cx23`, `cx33`, `cpx42`) und deren verfügbare Standorte (`nbg1`, `fsn1`, `hel1`) ab 2. **Dropdown-Matrix bauen** — erzeugt eine kombinierte Server-Type/Location-Liste im Format `cx23|nbg1` 3. **MinIO/S3 Upload** — schreibt beide JSON-Dateien ins S3-Backend unter `inventory/` 4. **KV-Store setzen** — speichert die Dropdown-Optionen unter dem Key `hetzner_server_type_location_options` Ausgaben: | Ziel | Pfad / Key | |---|---| | S3 | `inventory/hetzner-server-types.json` | | S3 | `inventory/hetzner-server-type-location-options.json` | | KV-Store | `hetzner_server_type_location_options` | Benötigte Kestra Secrets: ```text HCLOUD_TOKEN AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY TF_BACKEND_BUCKET TF_BACKEND_ENDPOINT ``` --- ### `hetzner-server-available-list.yaml` Kestra-Flow zum automatischen Abrufen aller laufenden Hetzner Cloud Server. **Namespace:** `hetzner` **Trigger:** Alle 15 Minuten, täglich 07:00–21:00 Uhr (Europe/Berlin) Der Flow: 1. **Hetzner API abfragen** — ruft alle vorhandenen Server ab (Name, Status, IPv4, Server-Typ, Standort, Labels, Erstelldatum) 2. **Servernamen extrahieren** — erzeugt eine separate JSON-Liste mit nur den Namen für Kestra-Dropdowns 3. **MinIO/S3 Upload** — schreibt beide JSON-Dateien ins S3-Backend unter `inventory/` 4. **KV-Store setzen** — speichert die Servernamen unter dem Key `hetzner_server_names` Ausgaben: | Ziel | Pfad / Key | |---|---| | S3 | `inventory/hetzner-server-available.json` (vollständige Serverdaten) | | S3 | `inventory/hetzner-server-names.json` (nur Namen) | | KV-Store | `hetzner_server_names` | Benötigte Kestra Secrets: ```text HCLOUD_TOKEN AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY TF_BACKEND_BUCKET TF_BACKEND_ENDPOINT ``` --- ### `hetzner-vm-destroy.yaml` Kestra-Flow zum sicheren Löschen einer Hetzner Cloud VM via Terraform — mit Destroy-Plan, manuellem Approval-Gate und automatischer Inventar-Aktualisierung. **Namespace:** `hetzner` **Trigger:** Manuell (kein Schedule) Der Flow läuft in vier Phasen: 1. **Terraform Destroy Plan** — erstellt einen Destroy-Plan für die gewählte VM; lädt den Terraform State aus dem S3-Backend 2. **Plan-Ausgabe loggen** — zeigt den vollständigen Destroy-Plan im Kestra-Log zur manuellen Prüfung 3. **Approval-Gate** — Kestra pausiert und wartet auf manuelle Freigabe 4. **Destroy / Abbruch** — bei Freigabe wird die VM gelöscht und anschließend automatisch der Subflow `hetzner-server-available-list` ausgeführt, um Inventar und KV-Store zu aktualisieren; bei Ablehnung wird abgebrochen Die VM wird per dynamischem Dropdown aus dem KV-Key `hetzner_server_names` ausgewählt (befüllt durch `hetzner-server-available-list`). Benötigte Kestra Secrets: ```text HCLOUD_TOKEN SSH_KEY_NAME AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY TF_BACKEND_BUCKET TF_BACKEND_ENDPOINT ``` --- ### `.env.example` Beispiel-Datei für benötigte Umgebungsvariablen und Secrets. Die Datei enthält bewusst nur Platzhalter. Die echte `.env` darf nicht ins Git-Repository committed werden. --- ## Installation Repository klonen: ```bash git clone https://git.unixweb.net/joachim/kestra-scripts.git cd kestra-scripts ``` Beispiel-Umgebung kopieren: ```bash cp .env.example .env ``` Danach die Werte in `.env` anpassen. --- ## Kestra Secrets Der Flow verwendet Kestra Secrets, zum Beispiel: ```yaml privateKey: "{{ secret('SSH_PRIVATE_KEY') }}" ``` Bei Kestra OSS müssen `SECRET_*` Werte in der `.env` base64-codiert hinterlegt werden. Beispiel Linux: ```bash echo -n "mein-geheimer-wert" | base64 -w 0 ``` Beispiel macOS: ```bash echo -n "mein-geheimer-wert" | base64 ``` Beispiel für einen SSH Private Key: ```bash base64 -w 0 ~/.ssh/id_ed25519 ``` Dann in `.env` eintragen: ```env SECRET_SSH_PRIVATE_KEY=base64_encoded_private_ssh_key ``` --- ## Docker Stack Inventory Scan Der Flow befindet sich in: ```text docker_stack_inventory_scan.yaml ``` Wichtige Variablen im Flow: ```yaml variables: ssh_user: meinuser base_dir: /home/meinuser/docker kv_select_options_key: docker_stack_select_options ``` Die Docker-Hosts werden im Flow als Liste definiert: ```yaml docker_hosts: - docker1;192.168.100.10 - docker2;192.168.100.11 ``` Format: ```text hostname;ip-adresse ``` Beispiel: ```text docker1;192.168.100.10 ``` --- ## KV-Store Ergebnis Der Flow schreibt die Dropdown-Liste in diesen Kestra KV-Key: ```text docker_stack_select_options ``` Die Werte haben dieses Format: ```text hostname;ip-adresse;ssh-user;compose-verzeichnis ``` Beispiel: ```text docker1;192.168.100.10;meinuser;/home/meinuser/docker/nextcloud ``` --- ## Sicherheit Dieses Repository darf keine echten Zugangsdaten enthalten. Nicht committen: ```text .env SSH Private Keys API Tokens Passwörter Terraform State Dateien S3 Zugangsdaten OpenAI API Keys SMTP Passwörter ``` Empfohlene `.gitignore`: ```gitignore .env .env.* !.env.example *.tfstate *.tfstate.* .terraform/ *.pem *.key id_rsa id_ed25519 __pycache__/ *.pyc ``` Wichtig: Wenn ein Secret einmal versehentlich committed oder öffentlich geteilt wurde, sollte es ausgetauscht werden. --- ## Test des Python-Scripts Das Python-Script kann lokal getestet werden. Beispiel: ```bash export OPTIONS_B64_JSON='["WyJkb2NrZXIxOzE5Mi4xNjguMTAwLjEwO21laW51c2VyOy9ob21lL21laW51c2VyL2RvY2tlci9uZXh0Y2xvdWQiXQ=="]' python3 build_select_options.py cat select_options.json ``` Erwartete Ausgabe: ```json [ "docker1;192.168.100.10;meinuser;/home/meinuser/docker/nextcloud" ] ``` --- ## Typische Fehler ### Python-Script wird nicht gefunden Fehler: ```text python3: can't open file ... build_select_options.py ``` Ursache: Das Script liegt nicht an der erwarteten Stelle im geklonten Repository. Lösung: Im Kestra-Log prüfen, welche Dateien nach dem Git-Clone vorhanden sind. Der aktuelle Flow sucht `build_select_options.py` automatisch. --- ### SSH-Verbindung schlägt fehl Mögliche Ursachen: * falscher SSH-Benutzer * falscher Host * SSH-Key fehlt in Kestra * Public Key ist auf dem Zielhost nicht in `authorized_keys` * Firewall blockiert Port 22 --- ### Keine Stacks gefunden Mögliche Ursachen: * falsches `base_dir` * Compose-Dateien liegen tiefer als `maxdepth 2` * Compose-Dateien heißen anders * Benutzer hat keine Leserechte --- ## Grundsatz Die klassische Aufteilung bleibt: ```text Kestra = Ablaufsteuerung Git = versionierte Logik Secrets = außerhalb des Repositories KV-Store = Laufzeitdaten für Dropdowns und Auswahlfelder ```