Skip to main content

Module floating_ip

Module floating_ip 

Source
Expand description

Provider-abstracted floating/reserved-IP mobility (R594-F5).

FloatingIpProvider is the domain-level trait each vendor adapter (HetznerFloatingIp, OvhFloatingIp, VultrFloatingIp — sibling modules in this directory) implements. reconcile_assignment is the shared idempotent + zone-checked core all three run through, so the “no-op when already assigned” / “reject a cross-zone move” behavior is written and tested exactly once instead of three times.

on_ingress_owner_changed is the Rust-level callable entry point for R594-F5’s ask: given the raft ingress_owner seam (oss/yubaba/crates/yubaba/src/raft/mod.rs’s YubabaRequest::SetIngressOwner / ClearIngressOwner, RaftAppState::ingress_owner) and the machine it currently names, command the provider floating IP to follow. Wiring this to fire automatically whenever ingress_owner transitions lives in the raft-apply / leadership-reconcile path (oss/yubaba/crates/yubaba/src/leader.rs), which is peer-owned and off-limits to this ticket — see on_ingress_owner_changed’s doc comment for the exact call site a follow-up should add. This is the same “mechanism now, wiring later” shape R594-F3 used for service records.

This mirrors, at the sovereign-ingress tier, the “external identity follows placement” property R591 names for Headscale via a Cloudflare Tunnel. R591 is peer-owned and gated on R570 (real multi-node raft HA); this module is not blocked on either — it builds directly on the ingress_owner seam, which already exists.

@yah:ticket(R859-F2, “Wire floating-ip.* provider adapters to ingress_owner transitions + health-checked DNS withdrawal for dead origins”) @yah:at(2026-09-04T19:06:57Z) @yah:status(open) @yah:assignee(agent:user-custom-char-gul2) @yah:parent(R859) @yah:next(“The verbs and adapters exist with zero callers: envoy/floating_ip.rs + provider/{vultr,hetzner,ovh}_floating_ip.rs are dead code today. Raft already holds and applies ingress_owner (raft/mod.rs:597,1182) — the missing piece is the effector that commands the provider when it changes, which is exactly W267 Tier 1’s ‘external identity follows placement’ (the R591 property).”) @yah:next(“Two failover speeds, both currently manual: intra-provider = floating-IP reassign (seconds, no DNS propagation, no cert re-mint — mind the W267-verified mobility constraints: Hetzner per network zone, OVH per DC region, Vultr region-bound); cross-provider = short-TTL DNS withdrawal of the dead origin’s A record (needs R859-F1’s rendering).”) @yah:next(“The health signal for withdrawal must NOT come from raft health (W267 §‘Where liveness lives’ — reachability is observer-relative); use the supervisor-level fact only: a machine leaving the fleet / its yubaba unreachable from quorum, not a per-proxy probe.”) @yah:next(“cloud.mesh_failover (W271) is the existing manual verb — keep it as the operator path; this ticket automates the effector both paths share.”) @yah:next(“Tier: Wizard — touches live-fleet failover semantics; wrong wiring here turns a leadership flap into a public outage. Design the guard rails (hysteresis, refuse-on-degraded-quorum per yubaba-failover.md) before the effector.”)

Structs§

FloatingIpAssignOutcome
Outcome of reconcile_assignment / on_ingress_owner_changed.
FloatingIpState
Current provider-side state of a floating/reserved IP.
FloatingIpTarget
A resolved reassign target: provider-native attach id + the mobility zone it lives in.

Traits§

FloatingIpProvider
One provider’s floating/reserved-IP transport + mobility policy.

Functions§

on_ingress_owner_changed
Callable entry point: react to the raft ingress_owner seam naming machine as the box that now owns public ingress, by commanding ip_id to follow it.
reconcile_assignment
Idempotent, zone-checked core shared by every provider adapter and by on_ingress_owner_changed.