gelkao invoice

Hetzner-Rechnungen herunterladen und auditieren.

BEZEICHNUNG

gelkao invoice - Hetzner-Rechnungen als CSV herunterladen und auditieren

ÜBERSICHT

cat data/*.html | ./gelkao invoice audit - [-g "<projekt>"] [-d <verzeichnis>] [-f <pfad>]
cat data/*.html | ./gelkao invoice list
cat data/*.html | ./gelkao invoice list | ./gelkao invoice fetch [-d <verzeichnis>]
printf 'K0000000000\n00000000-0000-0000-0000-000000000000\n' | ./gelkao invoice fetch [-d <verzeichnis>]
./gelkao invoice audit [-g "<projekt>"] [-d <verzeichnis>] [-f <pfad>]

BESCHREIBUNG

gelkao invoice lädt die detaillierten Hetzner-Rechnungen herunter und auditiert sie. Mit audit - wird der gesamte Ablauf ausgeführt: Rechnungs-HTML von der Standardeingabe (stdin) lesen, die Rechnungs-UUIDs extrahieren, jede Rechnung als CSV herunterladen und anschließend auditieren. Die einzelnen Schritte stehen auch als Subkommandos zur Verfügung. Der Download-Fortschritt wird auf die Standardfehlerausgabe (stderr) geschrieben, das Audit auf die Standardausgabe (stdout).

Auf invoice folgt immer ein Subkommando (list, fetch, audit); ohne Angabe bricht der Aufruf mit einem Fehler ab. Die Kundennummer wird aus der Rechnungsseite selbst gelesen – es ist also nichts einzutippen und nichts landet in der Shell-History.

Vor dem Audit bietet ein interaktiver Lauf an, die Preistabellen von gelkao.com zu aktualisieren ([Y/n]); bei Zustimmung werden die neuesten öffentlichen Preis- und Spezifikations-CSVs nach live/ heruntergeladen, die anschließend den eingecheckten Snapshot überschreiben. Mit n wird abgelehnt; mit -q (oder bei jedem nicht-interaktiven Lauf) wird die Abfrage übersprungen und gegen die bereits vorhandenen Tabellen gerechnet.

OPTIONEN

  • -g "<projekt>" – auditiert nur ein Hetzner-Projekt (die Spalte grouping der Rechnung, z. B. "Project prod"). Nur bei audit gültig; bei list oder fetch ein Fehler.
  • -d <verzeichnis> – Rechnungs-CSV-Verzeichnis (Vorgabe data). Gültig bei fetch und audit; bei list ein Fehler.
  • -f <pfad> – SQLite-Datenbankdatei (Vorgabe <verzeichnis>/gelkao.db). Gültig bei audit; bei list oder fetch ein Fehler.
  • -q – überspringt die interaktive Abfrage zur Preisaktualisierung und auditiert gegen die bereits vorhandenen Preise. Wird impliziert, wenn die Ausgabe kein Terminal ist (Pipe, CI).

UMGEBUNGSVARIABLEN

  • GELKAO_PRICES_URL – Basis-URL für die Preisaktualisierung (Vorgabe https://gelkao.com/live).
  • LIVE_DIR – Speicherort der aktualisierten Preistabellen (Vorgabe live).

BEFEHLE

gelkao invoice list

Liest das HTML der Hetzner-Seite „Rechnungen verwalten“ von der Standardeingabe und gibt die UUID jeder Rechnung aus, eine pro Zeile. Die UUIDs werden aus den Detail-Links der einzelnen Rechnungen in der Form https://usage.hetzner.com/<uuid> ausgelesen. Üblicherweise liegen die gespeicherten Rechnungsseiten im Verzeichnis data/.

AUSGABE – eine UUID pro Zeile, in der Reihenfolge der Seite. Nicht dedupliziert – beim Zusammenfügen mehrerer Seiten durch sort -u leiten (cat data/*.html | ...).

EXIT-STATUS – 0 UUIDs gefunden · 1 keine gefunden (gibt eine Warnung auf die Standardfehlerausgabe aus – üblicherweise hat Hetzner das URL-Schema geändert).

EINSCHRÄNKUNGEN – es werden nur Rechnungen ab dem 01.10.2024 aufgelistet. Der Detail-Link usage.hetzner.com/<uuid> gehört zum neuen Format für detaillierte Rechnungen, das Hetzner am 1. Oktober 2024 eingeführt hat; ältere Rechnungen verwenden numerische IDs (/invoice/<id>/pdf) ohne UUID und werden bewusst übersprungen. Sind alte Rechnungen vorhanden, ist mit weniger UUIDs als der Gesamtzahl der Zeilen auf der Seite zu rechnen.

cat data/invoice-list.html | ./gelkao invoice list
cat data/*.html | ./gelkao invoice list | sort -u

gelkao invoice fetch

Liest die Ausgabe von gelkao invoice list von der Standardeingabe – eine Zeile mit der Kundennummer (K…) und eine Rechnungs-UUID pro Zeile, in beliebiger Reihenfolge – und lädt jede detaillierte Rechnung als CSV von https://usage.hetzner.com/<uuid>?csv&cn=<kundennummer> herunter. Die Dateien werden in das Datenverzeichnis als <kundennummer>-<YYYY-MM>-<uuid>.csv geschrieben, wobei sich Jahr und Monat aus dem ersten ISO-Datum in der CSV ergeben. Da die UUID Teil des Dateinamens ist, wird eine bereits vorhandene Rechnung erkannt und vor dem Herunterladen übersprungen (der Monat wird bei der Suche als Platzhalter behandelt) – erneute Läufe und Wiederholungen verursachen somit keinen Netzwerk-Request für bereits erledigte Arbeit.

Die Kundennummer stammt aus dem Datenstrom, nicht aus einem Argument. -d <verzeichnis> legt das Ausgabeverzeichnis fest (Vorgabe data).

AUSGABE – ok-/skip-Fortschrittszeilen auf der Standardausgabe, fail-Zeilen auf der Standardfehlerausgabe und abschließend eine Zusammenfassung Done. downloaded=N skipped=N failed=N auf der Standardfehlerausgabe. Die CSV-Dateien landen im Datenverzeichnis.

EXIT-STATUS – 0 abgeschlossen (einzelne Download-Fehler werden gemeldet, brechen den Lauf jedoch nicht ab) · 1 keine K…-Zeile auf der Standardeingabe oder zwei verschiedene (Ausgaben zweier list-Läufe für verschiedene Accounts aneinandergehängt). Wiederholungen derselben Nummer sind unproblematisch.

ANMERKUNGEN – das Programm lädt sequenziell und ohne künstliche Verzögerung herunter, und das ist beabsichtigt. Eine Untersuchung des Endpunkts zeigt, dass er kein für den Client sichtbares Rate-Limit-Signal ausgibt: weder erfolgreiche (200) noch abgelehnte (401) Antworten von usage.hetzner.com enthalten RateLimit-*-, Retry-After- oder Kontingent-Header, und die Auslieferung erfolgt über Hetzners Edge-Cache (server: HeRay), nicht über die Cloud API – ein separates System mit einem dokumentierten Limit von 3600 Requests pro Stunde. Das Rechnungsvolumen ist gering (eine Datei pro Monat seit Einführung des Formats), und ein erneuter Lauf überspringt bereits heruntergeladene Rechnungen, ohne sie erneut abzurufen; ein unterbrochener oder gedrosselter Lauf lässt sich daher günstig wiederholen.

SICHERHEIT – für das Herunterladen einer Rechnung sind zwei unabhängige Geheimnisse erforderlich – die rechnungsspezifische UUID und die Kundennummer des Accounts (der als cn übergebene K…-Wert). Weder ein Browser-Login noch ein Session-Cookie ist beteiligt; die beiden Werte zusammen bilden die Zugangsdaten, ähnlich einem zweiten Faktor. Hinweise:

  • Eine UUID allein lädt nichts herunter – die passende Kundennummer muss ebenfalls angegeben werden. Diese Nummer ist jedoch für jede Rechnung des Accounts gleich und weist wenig Entropie auf, sodass die UUID, sobald die Nummer bekannt ist, praktisch das einzige rechnungsspezifische Geheimnis ist.
  • Beide Werte stehen in der gespeicherten Rechnungsseite; genau diese Datei ist daher das schützenswerte Artefakt.
  • Sowohl die UUID-Liste als auch die Kundennummer sind als sensibel zu behandeln, die heruntergeladenen CSVs als Abrechnungsdaten. data/ ist standardmäßig per gitignore ausgeschlossen – es aus der Versionsverwaltung, aus Protokollen (Logs), Tickets und geteilten Ablagen heraushalten.
printf 'K0000000000\n00000000-0000-0000-0000-000000000000\n' | ./gelkao invoice fetch
cat data/*.html | ./gelkao invoice list | ./gelkao invoice fetch

gelkao invoice audit

Mit - wird die Rechnungsseite von der Standardeingabe gelesen und der gesamte Ablauf ausgeführt – das entspricht gelkao invoice list, per Pipe an gelkao invoice fetch weitergegeben, gefolgt vom unten beschriebenen Audit. Die Kundennummer stammt aus der Seite, es ist also nichts zu übergeben. Das - darf vor oder nach den Optionen stehen.

Ohne - wird die Standardeingabe nie gelesen; es läuft direkt das Audit der bereits im Datenverzeichnis liegenden CSVs.

Baut eine wegwerfbare SQLite-Datenbank aus den Rechnungs-CSVs auf und gibt den Audit-Report aus. Die Tabellen werden aus schema.sql erstellt, jede *.csv im Datenverzeichnis wird in raw_invoices importiert, anschließend werden die Views aus audit.sql aufgebaut. Der Report besteht aus einem zusammenfassenden Kopf (Zeitraum, Währung, analysierte Server, Price Group, insgesamt bezahlt, aktuelle Run-Rate), einer einzeiligen Ersparnis-Angabe und einer monatsweisen Tabelle „bezahlt gegenüber optimal“ mit #-Balken. Auf einem Terminal werden die Zahlen fett dargestellt und Balken sowie Prozentwert jedes Monats nach Ersparnis-Stufe eingefärbt (rot ≥50 %, gelb 20–49 %, grün <20 %); bei einer Pipe oder Umleitung ist die Ausgabe schmucklos. Die Datenbank liegt unter <verzeichnis>/gelkao.db und ist ein wegwerfbarer Cache, der bei jedem Lauf aus den CSVs neu aufgebaut wird – ein Löschen ist unbedenklich.

-d <verzeichnis> legt den Ordner mit den Rechnungs-CSVs fest (Vorgabe data); -f <pfad> legt den Datenbankpfad fest (Vorgabe <verzeichnis>/gelkao.db). Exit-Status: 0 abgeschlossen · 1 keine Rechnungs-CSVs im Datenverzeichnis gefunden, oder – wenn eine Seite hineingegeben wurde – keine Kundennummer darin, zwei verschiedene, oder keine UUIDs.

cat data/*.html | ./gelkao invoice audit -
./gelkao invoice audit
./gelkao invoice audit -g "Project prod"
./gelkao invoice audit -d pages -f /tmp/x.db

← Zurück zur Dokumentation

Inhalt