Skip to content

feat!: Select NetworkRule backends by label - #29

Merged
privateip merged 1 commit into
mainfrom
feat/networkrule-backend-selector
Oct 8, 2026
Merged

privateip merged 1 commit into
mainfrom
feat/networkrule-backend-selector

Conversation

@privateip

@privateip privateip commented Oct 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

A NetworkRule names its backends as fixed addresses, and each backend's node also needs a hand-written ServiceVIPBinding before it answers on the VIP.

When an instance moves to another node or gets a new address, the gateway follows it but the binding does not, so connections to that backend drop while the rule still reports Accepted.

This API-only change lets a rule pick its backends with a label selector over VPCAttachments in its own VPC, and makes a binding record its VPC, so galactic can generate every binding (datum-cloud/galactic#799).

Breaking changes

NetworkRule drops its backend list and requires a selector and a backend port. ServiceVIPBinding requires a VPC reference.

Galactic's staging channel and its containerlab lab both install these CRDs from main, and galactic main still reads the backend list. Merge this together with the galactic pull request, right before it, so rules break only between the two merges.

PR #26 edits the same generated files. Whichever merges second has to regenerate them.

Test plan

  • A rule with a selector and backend port is accepted, and one with an empty selector or a static backend list is rejected
  • A ServiceVIPBinding without a VPC reference is rejected
  • Build, lint, unit tests and the e2e suite pass

Related to datum-cloud/galactic#799

🤖 Generated with Claude Code

@privateip
privateip marked this pull request as ready for review October 8, 2026 18:38
@privateip
privateip requested a review from a team as a code owner October 8, 2026 18:38
A NetworkRule listed its backends as fixed address:port pairs, and every backend's node needed a hand-written ServiceVIPBinding before it would answer on the VIP. When an instance was recreated on another node or with a new address, the gateway followed it but the binding did not, and the rule kept reporting Accepted while connections to that backend dropped.

NetworkRuleSpec.backends is replaced by two required fields. backendSelector is a label selector over cloud.datumapis.com/v1alpha1 VPCAttachments, matched against each attachment's own labels and limited to attachments whose status.vpc equals vpcRef, so a selector cannot reach another tenant. Each selected attachment contributes the IPv6 addresses in its spec.interface.addresses as backends, on backendPort. A CEL rule rejects an empty selector rather than reading it as every attachment in the VPC.

ServiceVIPBindingSpec gains a required vpcRef, copied from the owning rule. It names the tenant VRF the binding's translation rows go into, which replaces the consumer's search by backend address, a search that cannot tell apart two tenants using the same address range on one node. Both type comments now say galactic-router on each node generates these objects from the rules.

This change is the API only. The galactic side, the selector expansion in galactic-gateway and the binding writer in galactic-router, lands in the galactic pull request for datum-cloud/galactic#799, which pins this commit.

BREAKING CHANGE: NetworkRule spec.backends is removed and spec.backendSelector and spec.backendPort are required. ServiceVIPBinding spec.vpcRef is required. The galactic staging channel and the galactic containerlab lab both install these CRDs from main, and galactic main still reads spec.backends, so this merges together with the galactic change rather than ahead of it. No conversion is provided: the load balancer has no production deployment.

Related to datum-cloud/galactic#799

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@privateip
privateip force-pushed the feat/networkrule-backend-selector branch from 303abdb to 80e7f55 Compare October 8, 2026 18:42
@privateip privateip changed the title feat: Select load balancer backends by label instead of listing addresses feat!: Select NetworkRule backends by label Oct 8, 2026
@privateip
privateip merged commit 5775a87 into main Oct 8, 2026
6 checks passed
@privateip
privateip deleted the feat/networkrule-backend-selector branch October 8, 2026 18:57
privateip added a commit to datum-cloud/galactic that referenced this pull request Oct 8, 2026
A NetworkRule listed fixed backend addresses, and each backend's node needed a hand-written ServiceVIPBinding before it answered on the VIP. When an instance moved node or changed address, the gateway followed it but the binding did not, so the rule reported Accepted and Programmed while that backend's connections dropped.

datum-cloud/network#29 replaced spec.backends with backendSelector and backendPort and added a required vpcRef to ServiceVIPBinding. go.mod pins network main at the #30 merge, which carries both #29 and the private service types main already uses.

Gateway: buildDesiredRule expands the selector into the IPv6 interface addresses of the VPCAttachments it picks in the rule's own VPC, resolves each to the uSID of the node its attachment reports, and writes the backend's slot into that uSID. The reconciler watches VPCAttachments cluster-wide, so a backend that appears, moves or changes address reconverges every gateway. Selected attachments with no node or no IPv6 address show up under BackendsUnresolved.

galactic-router: NetworkRuleBindingReconciler writes one binding per selected backend on its own node for the rule's IPv6 VIP, owned by the rule, labelled with its node and managed-by, with egressKind from the attachment's interface mode, and deletes the ones that no longer apply. Each node writes only its own bindings, so there is one writer per object. The rule gains a per-node <node>/BackendsBound condition. ServiceVIPBindingReconciler resolves the VRF from the binding's vpcRef, which replaces the address-containment search and its TODO(dsr-maglev).

Both sides select backends through the same code, which also drops, in the same order everywhere, a backend whose address another attachment already claims or whose slot collides with another backend on its node, and reports it as unresolved rather than sending it flows it could not answer. A rule may carry at most one IPv6 VIP, because a backend node rewrites a reply's source to a single VIP; a rule with two fails to load and reports InvalidRule. A rule that loses Accepted, as it does whenever its namespace briefly has no NetworkGateway, keeps its bindings, so the backend nodes' vip_xlat_table rows survive until the gateways return.

RBAC: galactic-router can create and delete servicevipbindings, read networkrules and write their status. galactic-gateway can read vpcattachments. Both RBAC preflights check the new watches, and the gateway's also checks bgpvrfinstances, which it already watched.

Fixes #799

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants