feat(ci-ephemeral): provisioner circuit breaker and alert #9

Merged
jfraeys merged 3 commits from feat/provisioner-circuit-breaker into main 2026-10-02 19:02:09 -04:00
Owner

An expired Headscale preauth key made the provisioner create and destroy a billed VM every ~3.5 min indefinitely. Now 3 consecutive provisioning failures pause new cycles for 30 min, then allow one trial cycle; reaching running resets it. Failures count once per cycle; known causes (expired key, rejected SSH key, checksum mismatch) log a fixed hint without echoing output.

Breaker state is exported via node-exporter textfile metrics, and CIEphemeralProvisionerCircuitOpen (warning, for 2m) fires on it through the existing Alertmanager receiver. Tunables: ci_ephemeral_provisioner_breaker_threshold / _cooldown.

Tested: 10 unit tests (pytest roles/ci_ephemeral_provisioner/tests), promtool check rules on alerts.yml. Not run: a real provisioner cycle or alert delivery. Deploy needs services.yml for the provisioner and prometheus roles.

🤖 Generated with Claude Code

An expired Headscale preauth key made the provisioner create and destroy a billed VM every ~3.5 min indefinitely. Now 3 consecutive provisioning failures pause new cycles for 30 min, then allow one trial cycle; reaching running resets it. Failures count once per cycle; known causes (expired key, rejected SSH key, checksum mismatch) log a fixed hint without echoing output. Breaker state is exported via node-exporter textfile metrics, and CIEphemeralProvisionerCircuitOpen (warning, for 2m) fires on it through the existing Alertmanager receiver. Tunables: ci_ephemeral_provisioner_breaker_threshold / _cooldown. Tested: 10 unit tests (pytest roles/ci_ephemeral_provisioner/tests), promtool check rules on alerts.yml. Not run: a real provisioner cycle or alert delivery. Deploy needs services.yml for the provisioner and prometheus roles. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
An expired Headscale preauth key made the provisioner create and destroy a billed
VM every ~3.5 min indefinitely. Now N consecutive provisioning failures (default 3)
pause new cycles for a cooldown (default 30 min), then allow one trial cycle; a cycle
reaching running resets it. Failures count once per cycle, and known causes (expired
key, rejected SSH key, checksum mismatch) log a fixed hint without echoing output.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The breaker exports circuit_open/consecutive_failures via node-exporter's textfile
collector; CIEphemeralProvisionerCircuitOpen (warning, for 2m) fires on it and routes
through the existing Alertmanager receiver. Metrics rewrite every tick so clearing
breaker.json clears the alert; a metrics write failure never blocks provisioning.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Merge branch 'main' into feat/provisioner-circuit-breaker
Some checks failed
Lint / lint (pull_request) Failing after 15m1s
44167f4bf6
# Conflicts:
#	roles/ci_ephemeral_provisioner/tasks/main.yml
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
jfraeys/infra!9
No description provided.