refactor(cni): extract galactic-route as its own CNI chain plugin - #306
refactor(cni): extract galactic-route as its own CNI chain plugin#306privateip wants to merge 1 commit into
Conversation
d48f088 to
7f0a73f
Compare
7f0a73f to
a1e29e7
Compare
a1e29e7 to
96f0f09
Compare
Step 3 of the CNI plugin-chain split (galactic/plan-cni-plugin-chain):
pulls termination-route installation out of the veth and tap master
plugins into its own chained CNI binary, galactic-route, invoked
between the master plugin and galactic-bgp per conflist order. Unlike
every other binary in the chain, galactic-route has zero Kubernetes
dependency — it neither reads nor writes any CRD, and never needs a
namespace.
internal/cniroute is the new plugin package, mirroring the shape
established by cniipam/cnibgp:
- cniroute.go: RunPlugin() entrypoint (skel.PluginMainFuncs, ADD/DEL/
CHECK/STATUS/VERSION).
- types.go/config.go: PluginConf{VPC, VPCAttachment, Terminations},
parsed from stdin — the same document the master plugin itself
received, since the CNI runtime passes every chain entry its own
stanza plus prevResult. parseConf still reuses config.CNIConfig for
LogFile/LogLevel's env-var > conflist > default precedence (so
logging behaves identically to every other binary), but — unlike
galactic-bgp — never resolves NodeName or Kubeconfig, since nothing
here ever talks to the API server.
- ops_add.go: cmdAdd installs each termination as a VRF route via the
existing internal/cni/route package (route.Add), deriving the host
device name from (vpc, vpcAttachment) alone via
intf.GenerateInterfaceNameHost — identical for a veth master's host
end and a tap master's tap device, so galactic-route needs no
interface-kind inference the way galactic-bgp does. It then passes
prevResult through unchanged, adding no interfaces or IPs of its
own. Requires a non-nil prevResult (galactic-route must be chained
after a master plugin) and reads it from RawPrevResult, not the
never-populated typed PrevResult field.
- ops_del.go: cmdDel is a no-op, same as every other binary in the
chain — termination routes are keyed by (vpc, vpcAttachment) and may
still be in use by another pod/VM sharing the same attachment, so
cleanup is left entirely to galactic-router's GC controller. This
matches the pre-split behavior too: the old monolithic plugin's own
DEL never deleted termination routes either, for the same reason —
extracting this into its own binary changes nothing about when
routes actually get removed.
- ops_check.go: cmdCheck is checkTerminationRoutes, moved unchanged
from internal/cni/ops_check.go (also mirrored in internal/cnitap).
cmdStatus is a trivial always-ready success — galactic-route has
nothing external to probe, matching galactic-ipam's own STATUS,
implemented for uniformity across the chain per the plan's decision
rather than skipped.
- resource.go: a resourceTracker scoped to exactly what galactic-
route's own ADD creates — the termination routes it actually
installed (route-delete only). Rollback deletes only the routes
recorded as added, never routes a failed route.Add call never
reached.
internal/cni and internal/cnitap: dropped the Terminations field from
each PluginConf (both packages had their own copy of a Termination
type, now living only in cniroute since neither master plugin reads
"terminations" out of its own stanza anymore), the route.Add loop and
routesCreated tracker field from ops_add.go/resource.go, and the
checkTerminationRoutes call from ops_check.go's CHECK path (the
function itself moved to cniroute, verbatim).
Taskfile.yaml, containers/galactic-cni/Dockerfile, and
internal/installer/installer.go (SourceRouteBinary) gain galactic-route
alongside the four other chain binaries, following the exact pattern
established for those in steps 0-2.
Verification: task lint (0 issues), task build (all 8 binaries,
including galactic-route), task test:unit all green.
internal/cniroute lands at 62.9% coverage — its first-ever test
coverage, since internal/cni/route (the package it wraps) had none
before this split either; backfilling that package's own tests is
unrelated to this split's scope and left as-is. task test:e2e not run
in this step, same caveat as steps 0-2 (requires sudo modprobe vrf plus
a Kind cluster bring-up, deferred to the end of the full stack per the
plan's verification approach).
96f0f09 to
c1704f7
Compare
|
Reviewed this one. Overall it's a clean, careful mirror of the sibling packages (cnibgp, cnitap), the resource tracking, rollback, and prevResult handling all follow the established pattern. Two real bugs turned up, though, one of which will break at runtime despite tests and vet passing.
Two lower-severity things. The netns-override miss is the one I'd block on, it'll break every VM/tap workload with terminations despite the test suite being green. The CHECK bug on on-link routes is worth fixing too since it's a genuine functional bug, just inherited rather than introduced by this PR. |
Stack (merge bottom to top):
Summary
Fourth branch in the CNI plugin-chain split stack (based on #305).
galactic-routeis now its own chained CNI plugin — invoked between the master plugin andgalactic-bgpper conflist order — instead of termination-route installation insidegalactic-cni/galactic-tap-cni. Unlike every other binary in the chain, it has zero Kubernetes dependency: no CRD reads or writes, no namespace.What moved
internal/cniroutemirrorscniipam/cnibgp's shape:RunPlugin(),PluginConf{VPC, VPCAttachment, Terminations}.parseConfreusesconfig.CNIConfigfor LogFile/LogLevel precedence but never resolves NodeName or Kubeconfig — nothing here talks to the API server.cmdAddinstalls each termination as a VRF route via the existinginternal/cni/routepackage, deriving the host device name from(vpc, vpcAttachment)alone — identical for a veth master's host end and a tap master's tap device, so no interface-kind inference is needed the waygalactic-bgpneeds it. It requires a non-nilprevResultand passes it through unchanged.cmdDelis a no-op, matching the pre-split behavior: the old monolithic plugin's own DEL never deleted termination routes either — they're keyed by(vpc, vpcAttachment)and may still be in use by another pod/VM, so cleanup stays withgalactic-router's GC controller.cmdCheckischeckTerminationRoutes, moved unchanged.cmdStatusis a trivial always-ready success, matchinggalactic-ipam's own STATUS.Rollback scoping
resourceTrackercovers only the termination routes this plugin's own ADD actually installed (route-delete only) — rollback never touches a route a failedroute.Addcall never reached.Master plugin cleanup
internal/cni/internal/cnitapdrop theTerminationsfield from their ownPluginConf(each had its own copy of aTerminationtype — now lives only incniroute), theroute.Addloop androutesCreatedtracker field, and thecheckTerminationRoutescall from CHECK.Verification
task lint✅task build(all 8 binaries) ✅task test:unit✅internal/cnirouteat 62.9% coverage — its first-ever coverage, sinceinternal/cni/route(the package it wraps) had none before this split either. Backfilling that package's own tests is out of scope here.task test:e2enot run, same caveat as refactor(cni): split galactic-cni into veth/tap master plugins #303/refactor(cni): extract galactic-ipam as a real delegated CNI IPAM plugin #304/refactor(cni): extract galactic-bgp as its own CNI chain plugin #305.🤖 Generated with Claude Code