From e2cb2eabba9763f3cb010a6fe5bdf75d7adbce4b Mon Sep 17 00:00:00 2001 From: Joachim Hummel Date: Fri, 26 Jun 2026 18:03:17 +0200 Subject: [PATCH] add hetzner-server-type-location-update flow and document it in README Co-Authored-By: Claude Sonnet 4.6 --- README.md | 35 ++++++++ hetzner-server-type-location-update.yaml | 102 +++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 hetzner-server-type-location-update.yaml diff --git a/README.md b/README.md index d16bcac..d77157e 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,7 @@ Aktuell enthalten: * `build_select_options.py` * `linux_apt-upgrade.yaml` * `hetzner-vm-provision.yaml` +* `hetzner-server-type-location-update.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. @@ -138,6 +139,40 @@ 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 +``` + +--- + ### `.env.example` Beispiel-Datei für benötigte Umgebungsvariablen und Secrets. diff --git a/hetzner-server-type-location-update.yaml b/hetzner-server-type-location-update.yaml new file mode 100644 index 0000000..50f1bfc --- /dev/null +++ b/hetzner-server-type-location-update.yaml @@ -0,0 +1,102 @@ +id: hetzner-server-type-location-update +namespace: hetzner + +triggers: + - id: every-15-minutes-daytime + type: io.kestra.plugin.core.trigger.Schedule + cron: "*/15 7-21 * * *" + timezone: Europe/Berlin + + +tasks: + - id: fetch_server_types + type: io.kestra.plugin.scripts.shell.Commands + containerImage: alpine:latest + env: + HCLOUD_TOKEN: "{{ secret('HCLOUD_TOKEN') }}" + beforeCommands: + - apk add --no-cache curl jq + commands: + - | + set -eo pipefail + + curl -sS \ + -H "Authorization: Bearer $HCLOUD_TOKEN" \ + "https://api.hetzner.cloud/v1/server_types" \ + | jq -c ' + [ + .server_types[] + | select(.name == "cx23" or .name == "cx33" or .name == "cpx42") + | { + name: .name, + description: .description, + cores: .cores, + memory: .memory, + disk: .disk, + locations: [ + .prices[] + | select(.location == "nbg1" or .location == "fsn1" or .location == "hel1") + | .location + ] | unique + } + ] + ' > hetzner-server-types.json + + jq -c ' + [ + .[] + | .name as $type + | .locations[] + | "\($type)|\(.)" + ] + ' hetzner-server-types.json > hetzner-server-type-location-options.json + + echo "Server-Type/Location Matrix:" + cat hetzner-server-types.json + + echo "Dropdown-Optionen:" + cat hetzner-server-type-location-options.json + + outputFiles: + - hetzner-server-types.json + - hetzner-server-type-location-options.json + + - id: upload_to_minio + type: io.kestra.plugin.scripts.shell.Commands + containerImage: minio/mc:latest + env: + AWS_ACCESS_KEY_ID: "{{ secret('AWS_ACCESS_KEY_ID') }}" + AWS_SECRET_ACCESS_KEY: "{{ secret('AWS_SECRET_ACCESS_KEY') }}" + TF_BACKEND_BUCKET: "{{ secret('TF_BACKEND_BUCKET') }}" + TF_BACKEND_ENDPOINT: "{{ secret('TF_BACKEND_ENDPOINT') }}" + inputFiles: + hetzner-server-types.json: "{{ outputs.fetch_server_types.outputFiles['hetzner-server-types.json'] }}" + hetzner-server-type-location-options.json: "{{ outputs.fetch_server_types.outputFiles['hetzner-server-type-location-options.json'] }}" + commands: + - | + set -eo pipefail + + mc alias set tfstate "$TF_BACKEND_ENDPOINT" "$AWS_ACCESS_KEY_ID" "$AWS_SECRET_ACCESS_KEY" + + mc cp hetzner-server-types.json "tfstate/$TF_BACKEND_BUCKET/inventory/hetzner-server-types.json" + mc cp hetzner-server-type-location-options.json "tfstate/$TF_BACKEND_BUCKET/inventory/hetzner-server-type-location-options.json" + + echo "Server-Type/Location-Liste wurde nach MinIO/S3 geschrieben." + + - id: set_options_kv + type: io.kestra.plugin.core.kv.Set + key: hetzner_server_type_location_options + kvType: JSON + value: "{{ read(outputs.fetch_server_types.outputFiles['hetzner-server-type-location-options.json']) }}" + + - id: log_result + type: io.kestra.plugin.core.log.Log + message: | + ✅ Hetzner Server-Type/Location-Liste wurde aktualisiert. + + MinIO/S3: + s3://{{ secret('TF_BACKEND_BUCKET') }}/inventory/hetzner-server-types.json + s3://{{ secret('TF_BACKEND_BUCKET') }}/inventory/hetzner-server-type-location-options.json + + Kestra KV: + hetzner_server_type_location_options