Skip to content

fix(hetzner): check for stray floating IPs on every cluster update - #7838

Draft
devantler wants to merge 1 commit into
mainfrom
claude/hetzner-stray-floating-ip-every-update-7695
Draft

devantler wants to merge 1 commit into
mainfrom
claude/hetzner-stray-floating-ip-every-update-7695

Conversation

@devantler

Copy link
Copy Markdown
Contributor

🤖 Generated by the Agentic Engineer

Why

KSail warns when a Hetzner cluster has a floating IP address it labelled but no longer uses, because that address is billed while it exists. The warning only appeared when an update also changed the cluster's endpoint or control plane, so routine updates never said whether such an address exists.

What

Every update of a Hetzner cluster with a floating IP now checks for these addresses and says so either way, naming any it finds or stating that none were found. The check only reads, never stops the update, and is skipped for clusters without a floating IP.

🤖 Generated with Claude Code

Fixes #7695

KSail warns about floating IPs it labelled for a cluster but does not manage,
because such an address is billed while it exists. The check only ran when
an update re-rendered the floating-IP endpoint, which happens on creation,
on endpoint drift and on a control-plane change, so an ordinary update of a
Hetzner cluster with a floating IP endpoint never reported a stray address.

Run the same read-only check when an update changes neither the endpoint
nor the control plane, and print a line when it finds nothing, so a log
without a warning reads as "checked, none found" rather than "never
checked". A failed lookup is still reported and never fails the update, and
a cluster without a floating IP endpoint makes no floating-IP call.

Fixes #7695

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@devantler devantler left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Generated by the Agentic Engineer (interactive Claude Code session)

Self-review (fallback — CodeRabbit, Codex and Cursor Bugbot unavailable)

Reviewed commit: 8049d92cd203d55a58955b34e160d6b2fc6fe6c3

  • CodeRabbit: the account's free OSS review limit is used up — command reply 6230288024 ("Review rate limited", 05:40:32Z) and summary 6230288768 ("You've used all free OSS reviews for now", 05:40:38Z) on ksail#7822; recovers when that limit resets. No CodeRabbit artifact exists on this PR.
  • Codex: usage limit reached — reply 6230189816 on ksail#7823 (05:29:03Z); account-wide, recovers at its weekly reset.
  • Cursor Bugbot: usage limit reached — reply 6230200017 on ksail#7823 (05:30:20Z); account-wide, recovers when the usage limit resets.

Scope read: the new no-change branch in the floating-IP update step, the new check helper, the added "none found" line, the adjusted test comment and the four new tests. Checked: the check runs only when the update changes neither the endpoint nor the control plane, so no path now runs it twice; it is skipped unless the floating IP endpoint is enabled, and a cluster without one makes no floating-IP call; it only lists addresses — no ensure, attach or release — and a missing Hetzner provider or a failed listing prints the existing warning and returns, so the update step still succeeds; the "none found" line prints only after a successful listing, so a failed lookup is never reported as clean. The tests drive the real update step against a fake Hetzner API and count the label listings through the client transport: a stray address is named, a clean account prints the "none found" line, a failed lookup prints the warning, the disabled case makes no call, and no case attaches the address. With the new call removed, the three enabled cases fail; with it, the whole provisioner package (1085 tests) passes and lint is clean.

Verdict: no P0/P1 findings

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer (interactive Claude Code session)

Readiness at 8049d92cd203d55a58955b34e160d6b2fc6fe6c3 — one condition open

  • Programmatically tested: four new tests drive the real update step against a fake Hetzner API; the three enabled cases failed with the new call removed and pass with it, and the whole Talos provisioner package passes locally (1085 tests). CI at this head is still running.
  • Reviewed: local review round 5556588377 at this head, clean.
  • Evaluated as a user — not yet, and named: the change shows only on a ksail cluster update of a real Hetzner Talos cluster with the floating IP endpoint enabled, which this host cannot reach. Gate: read a Hetzner system-test run at this head whose floating-IP update trial prints either a stray-address warning or "No stray floating IPs labelled for this cluster" on an update that changes neither the endpoint nor the control plane. This stays a draft until that run is read.

@github-actions

Copy link
Copy Markdown
Contributor

@github-code-quality

Copy link
Copy Markdown
Contributor

Code coverage overview

Languages: Go

Go / code-coverage/go

main ffe71ae claude/hetzner-stray... 8049d92 +/-
72% 72% 0%
View coverage of the 10 most impacted files.
File main ffe71ae claude/hetzner-stray... 8049d92 +/-
pkg/client/reconciler/poll.go 86% 80% -6%
pkg/svc/install...cd/installer.go 100% 97% -3%
pkg/cli/cluster...i/distconfig.go 81% 79% -2%
pkg/svc/provisi...pgrader_wait.go 95% 94% -1%
pkg/svc/provisi...cale_hetzner.go 48% 48% 0%
pkg/cli/cmd/clu...values_drift.go 100% 100% 0%
pkg/svc/provisi...oner_hetzner.go 52% 53% +1%
pkg/svc/mirror/...unnelsession.go 97% 98% +1%
pkg/cli/cmd/clu...r/reconciler.go 72% 74% +2%
pkg/svc/install...site_removal.go 91% 93% +2%

ℹ️ Calculations represent line coverage. Results may change as calculations are updated.

@devantler

devantler commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

Blocker: the next free autonomous real-cluster trial slot (at most one per day portfolio-wide). 2026-10-18 and 2026-10-19 are used (the combined EKS trial for ksail#7823/#7852), 2026-10-20 is taken by ksail#7854, so this is no earlier than 2026-10-21. ksail#7870 also waits for a Hetzner cluster that day; both changes can be tried on one Hetzner cluster (an update for this one, a stop for #7870) | outcome | last-verified 2026-10-19: head 8049d92 is tested and its checks are green, with no conflicts but 19 commits behind main (the branch is updated right before the trial, so the trial runs the merged head and gets a fresh review); the only open readiness item is the user evaluation on a real Hetzner cluster

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: 🫴 Ready

Development

Successfully merging this pull request may close these issues.

Hetzner update never checks for stray floating IPs unless the endpoint or control plane changes

1 participant