Polycrate API 0.16.1¶
Release-Datum: 27. April 2026
Typ: Fix
Highlights¶
- DNSZone-Provisioning stabalisiert – Drei zusammenhängende Bugs beim Erstellen interner DNS-Zonen behoben: doppelter
provision()-Aufruf, nicht-idempotenter PowerDNS-API-Call und Transaction-Poisoning durchProductizedModelMixin(Specs 211, 212, 214). - AttributeError in
_integrity_error_responsebehoben – Logger-Shadowing inviews.pyverursachte HTTP 500 statt HTTP 409 bei UniqueConstraint-Verletzungen (Spec 210).
Details zu einzelnen Specs: polycrate spec inspect <id> im Workspace polycrate-api.
Artefakte¶
Docker Image¶
Block¶
Fixes¶
Logger-Shadowing in _integrity_error_response (Spec 210)¶
src/polycrate_api/views.py importierte polycrate_api.logging.logger (eine Klasse, keine Logger-Instance) nach der Modul-Level-Definition logger = logging.getLogger(__name__). Dieser Import überschrieb die Variable, sodass _integrity_error_response beim Aufruf von logger.warning(...) mit AttributeError: type object 'logger' has no attribute 'warning' abbrach.
Auswirkung: POST auf bereits existierende Ressourcen (z.B. K8sCluster) lieferte HTTP 500 statt HTTP 409, der Polycrate Operator retried dadurch endlos.
Fix: _integrity_error_response nutzt jetzt logging.getLogger(__name__).warning(...) direkt — unabhängig von der Modul-Level-Variable.
DNSZone-Provisioning: Doppelter provision()-Aufruf (Spec 214)¶
DNSZoneCreateForm.save() rief zone.provision() intern auf. Anschließend rief form_valid() in polycrate_api/views.py nochmals self.object.provision() auf — sync_to_powerdns() wurde damit bei jedem Erstellen einer Zone zweimal ausgeführt. Vor Spec 211 (nicht-idempotenter create_zone()-Call) resultierte der zweite Aufruf direkt in einem 409 Conflict.
Fix: provision() wurde aus DNSZoneCreateForm.save() entfernt. form_valid() übernimmt das Provisioning alleinig innerhalb seiner transaction.atomic()-Grenze.
DNSZone-Provisioning: Nicht-idempotenter PowerDNS-API-Call (Spec 211)¶
DNSZone.sync_to_powerdns() verwendete client.create_zone() (nicht-idempotenter POST). War die Zone bereits in PowerDNS vorhanden (z.B. durch Litestream-Restore aus S3), schlug der Call mit 409 Conflict fehl — die Zone existierte danach in PowerDNS, aber nicht in der Polycrate-API-Datenbank.
Fix: Wechsel auf client.ensure_zone_exists() (GET-then-POST): existierende Zonen werden zurückgegeben, nicht erneut angelegt.
DNSZone-Provisioning: Transaction-Poisoning durch ProductizedModelMixin (Spec 212)¶
ProductizedModelMixin._post_save rief reconcile_organization_product() innerhalb eines transaction.atomic(savepoint=True)-Blocks auf. Schlug der Savepoint fehl, setzte Django connection.needs_rollback = True — die äußere Transaktion (aus perform_create/form_valid) war damit vergiftet. Folgeoperationen (z.B. self.save(update_fields=["powerdns_metadata"]) am Ende von sync_to_powerdns()) schlugen mit TransactionManagementError fehl und rollten den DB-Eintrag zurück, während die Zone in PowerDNS bereits angelegt war.
Fix: _post_save und _post_delete nutzen jetzt transaction.on_commit() statt einem internen Savepoint. Die Pricing-Reconciliation läuft erst nach erfolgreichem Commit der äußeren Transaktion — wenn die Transaktion rollt zurück, feuert der Callback nie.
Kompatibilität und Deployment¶
- Kein Breaking Change, keine Datenbankmigrationen.
- Betrifft alle Deployments die interne DNS-Zonen (PowerDNS) verwenden.