Repository navigation
dhcp: serve pinned ranges on every cluster node (slice 8b) - #638
Conversation
Slice 8b of the DHCP design (docs/design/dhcp.md §3). Primary and replica alike now serve the ranges pinned to them and answer every reservation; a node still joining holds the primary's [dhcp] without serving it (F30). - The node whose sable.toml is edited refuses a range without a node, a node that isn't a member, and enabling while a member runs an older release than its own (strict TOML). Replicas only hold what the primary sends (F29). Standalone, a range may name only this node. - On a cluster the engine leaves unpinned ranges out, so a replica holding settings its primary refused never leases from them; a node with no range and no reservation doesn't bind port 67. - Each node allocates only from its own ranges and stays silent for an on-link address it doesn't own (RFC 2131 §4.3.2), so a partition never leases an address twice; a test drives two partitioned engines. - The other-server probe treats peers as this node (D36): peers' addresses aren't another server, and probes carry the cluster tag in option 60 (RFC 2132 §9.13) so peers drop them instead of holding an offer. - The primary publishes names for every node's mirrored leases (D61).
…eat/dhcp-cluster-serve
|
Review of #638 (slice 8b, serve on a cluster) at dd062a1: block. One finding takes DHCP off the whole network; three more need fixing with it. Run on two real nodes, each in its own network namespace on one bridge, port 67, real clients, including a node killed, a promote, a rolling update and a member removed:
Findings:
With the fix applied all five tests pass, the dhcp, app, cluster, web and config tests pass, and the cluster script passes with nothing filed. Not filed:
|
…ranted At start a node serves the ranges pinned to it: removed members and older releases are refused only where [dhcp] is edited (D63), so a restart after removing a dead member or updating the primary first no longer leaves the network without DHCP (F56, F57). An unpinned range is still refused on a primary. Removing a lease is replica-local and skips the replica refusal, since only the node that granted it holds it (D64, F58). The engine ends a client's other leases only on its own node; another node's row is that node's to write (F59, design §3).
# Conflicts: # internal/web/routes.go
What changed
Blake's two-node run on real port-67 namespaces passes at 34a707a with F56-F59 fixed (C169), and the suite and CI are green (C170).
Red, then green
export PATH=/usr/local/go/bin:$PATH GOEXPERIMENT=jsonv2; go test -count=1 -run 'TestDHCPServesOnEveryClusterNode|TestDHCPClusterNodeLeavesUnpinnedRangesAlone|TestDHCPClusterCheck|TestDHCPProbeTreatsClusterPeersAsThisNode|TestDHCPServiceRefusesUnpinnedRangeOnCluster|TestDHCPNamesOnlyWhereDHCPIsServed|TestDHCPClusterRole' ./internal/app/ && go test -count=1 -run 'TestClusterPartitionNeverLeasesAnAddressTwice' ./internal/dhcp/Checks
export PATH=/usr/local/go/bin:$PATH GOEXPERIMENT=jsonv2; go test -count=1 ./internal/app/ ./internal/dhcp/ ./internal/config/ ./docs/ && go test -count=1 -tags integration -run 'TestClusterReplica.*DHCP' ./internal/app/ && test -z "$(gofmt -l internal docs)", exit 0export PATH=/usr/local/go/bin:$PATH GOEXPERIMENT=jsonv2; cd /home/peak/work/dhcp-server-for-sable/sable-8b && go test -count=1 -run 'TestDHCPServesOnEveryClusterNode|TestDHCPClusterNodeLeavesUnpinnedRangesAlone|TestDHCPClusterCheck|TestDHCPProbeTreatsClusterPeersAsThisNode|TestDHCPServiceRefusesUnpinnedRangeOnCluster|TestDHCPNamesOnlyWhereDHCPIsServed|TestDHCPClusterRole' ./internal/app/ && go test -count=1 -run 'TestClusterPartitionNeverLeasesAnAddressTwice' ./internal/dhcp/, exit 0./cluster-prove.sh, exit 0export PATH=/usr/local/go/bin:$PATH GOEXPERIMENT=jsonv2; cd /tmp/p638 && go test -count=1 ./internal/app/ ./internal/dhcp/ ./internal/web/ ./internal/config/ ./internal/cluster/, exit 0FILED= ./cluster-prove.sh, exit 0export PATH=/usr/local/go/bin:$PATH GOEXPERIMENT=jsonv2; cd /tmp/pv638 && test "$(git diff -M --numstat 57b917e 34a707a | awk '{a+=$1+$2} END{print a+0}')" = 0 && go test -count=1 ./internal/app/ ./internal/dhcp/ ./internal/web/ ./internal/config/ ./internal/cluster/ ./docs/ && test -z "$(gofmt -l internal docs)", exit 0export PATH=/usr/local/go/bin:$PATH GOEXPERIMENT=jsonv2; cd /tmp/pv638 && go test -count=1 ./internal/app/ ./internal/dhcp/ ./internal/web/ ./internal/config/ ./internal/cluster/ ./docs/ && test -z "$(gofmt -l internal docs)", exit 0FILED= ./cluster-prove.sh, exit 0./run-suite.sh 638 /home/peak/work/dhcp-server-for-sable/sable-638, exit 0export PATH=/usr/local/go/bin:$PATH GOEXPERIMENT=jsonv2; cd /tmp/pv638 && go test -count=1 ./internal/app/ ./internal/dhcp/ ./internal/web/ ./internal/config/ ./internal/cluster/ ./docs/, exit 0export PATH=/usr/local/go/bin:$PATH GOEXPERIMENT=jsonv2; cd /tmp/pv638 && go test -count=1 ./internal/app/ ./internal/dhcp/ ./internal/web/ ./internal/config/ ./internal/cluster/ ./docs/ && test -z "$(gofmt -l internal docs)", exit 0export PATH=/usr/local/go/bin:$PATH GOEXPERIMENT=jsonv2; cd /tmp/pv638 && go test -count=1 ./internal/app/ ./internal/dhcp/ ./internal/web/ ./internal/config/ ./internal/cluster/ ./docs/, exit 0Found and fixed
Risks
Not run: three nodes, Postgres cluster, a relay. Full ./... takes ~20 min on this box; run internal/dhcp, internal/cluster, internal/web with GOFLAGS=-p=1 GOEXPERIMENT=jsonv2 to finish. Known unrelated: internal/outbound TestHTTPClientResolvesThroughSable fails here (proxy), and clusterfault TestRecoveryPromotionKeepsSOASerialsMonotonic is a pre-existing race on main (D66).
Prover
Passed (Sonnet): At 34a707a I reran the app, dhcp, web, config, cluster and docs packages (all pass, including the F56-F59 review tests) and found no defect. Untested: two real nodes on port 67 (relied on Blake's C169) and the stale console "can't serve" text (cosmetic).
Every command above was run by Fortysix's Basecamp itself, on the branch named.