Expand description
Provider-abstracted floating/reserved-IP mobility and ingress failover (R594-F5, R859-F2).
FloatingIpProvider is the domain-level trait each vendor adapter
implements; reconcile_assignment is the shared idempotent + zone-checked
core all of them run through, so the “no-op when already assigned” /
“reject a cross-zone move” behaviour is written and tested exactly once
instead of once per vendor. plan_ingress_owner_effect is the pure
decision layer above them: given a raft ingress_owner observation, what
should public ingress do?
§Why this is its own crate
It was cloud::provider::floating_ip until 2026-09-08. R859-F2 landed
plan_ingress_owner_effect with no production caller, because the caller
belongs in yubaba’s scheduler tick and a runtime yubaba -> cloud
dependency was not a courier’s call to make: cloud/Cargo.toml’s
yah-local-driver comment records R374-F3 carving that crate out of
cloud specifically to avoid such an edge, and taking it here would pull
velveteen, velveteen-exec, yah-hetzner, yah-mesofact-bundle and yah-almanac
into the release daemon shipped to every fleet node. The operator’s answer
(2026-09-08) was to repeat R374-F3’s move rather than reverse it — hence
this crate, which both cloud and yubaba depend on and neither owns.
So the dependency budget here is load-bearing, not tidiness: anyhow and
async-trait, and nothing else, forever. A reqwest or a serde in this
manifest ships to every node in the fleet.
§What is above this crate, and where
Two consumers, and this crate depends on neither:
yah-floating-ip-adapters— the Hetzner/OVH/Vultr HTTP clients that implementFloatingIpProvider. They were inclouduntil R859-F3 moved them one layer down soyubaba’s ingress effector could actually issue a reassign rather than only decide on one. That crate carries thereqwestthis one refuses to.yah-cloud— thefloating_ip.*envoy verb layer (cloud::provider::floating_ip_envoy) and the credentialed constructorcloud::provider::floating_ip::floating_ip_provider_for, which resolves vault slots throughfob. Neither an envoy catalog nor a credential vault belongs on a fleet node, so neither moved.
This crate holds the seam, the shared core, and the decision logic.
§The machine facts this layer needs
FloatingIpMachine is a five-field value, not cloud’s MachineConfig.
That is what makes the crate free of cloud: the adapters only ever read
name, location, region, provider and ingress_floating_ip off a
machine, so those five fields are the whole of the contract. cloud
converts at the boundary (impl From<&MachineConfig> for FloatingIpMachine)
and yubaba can build one from whatever it knows about a node without
being able to construct a MachineConfig at all — which it cannot, since a
fleet node has no .yah/infra/machines/ tree.
This mirrors, at the sovereign-ingress tier, the “external identity follows placement” property R591 names for Headscale via a Cloudflare Tunnel.
Structs§
- Floating
IpAssign Outcome - Outcome of
reconcile_assignment/on_ingress_owner_changed. - Floating
IpMachine - The machine facts floating-IP mobility actually needs — the whole contract between this crate and whatever declares machines.
- Floating
IpState - Current provider-side state of a floating/reserved IP.
- Floating
IpTarget - A resolved reassign target: provider-native attach id + the mobility zone it lives in.
Enums§
- Ingress
Owner Effect - What should happen to public ingress, given an
ingress_ownerobservation. - Owner
Liveness - What a
TransitionTracker-style hysteresis says about one machine, crossed into this crate as plain data. - Quorum
Health - Live consensus health, crossed into this crate as plain data.
Constants§
- FLOATING_
IP_ PROVIDERS - Which providers ship a
FloatingIpProvideradapter, and the credential each one authenticates with —(provider id, vault slot, env fallback).
Traits§
- Floating
IpProvider - One provider’s floating/reserved-IP transport + mobility policy.
Functions§
- on_
ingress_ owner_ changed - Callable entry point: react to the raft
ingress_ownerseam namingmachineas the box that now owns public ingress, by commandingip_idto follow it. - plan_
ingress_ owner_ effect - Decide what public ingress should do about an
ingress_ownerobservation — pure, so the decision is testable as arithmetic and the I/O is somebody else’s problem. - provider_
has_ floating_ ip_ adapter - Does
providerhave a floating-IP adapter at all? - reconcile_
assignment - Idempotent, zone-checked core shared by every provider adapter and by
on_ingress_owner_changed. - resolve_
ingress_ owner - Resolve an
ingress_ownerstring to the machine it names. - supported_
floating_ ip_ providers - The provider ids that ship an adapter, for an error message that names what is supported rather than only what is not.