From ffca7330c5e4090bbf88f7c8de94841b73a23598 Mon Sep 17 00:00:00 2001 From: Ben Duncan <5178243+benduncan@users.noreply.github.com> Date: Tue, 24 Mar 2026 16:27:28 +1000 Subject: [PATCH] =?UTF-8?q?fix:=20skip=20external=20IPAM=20init=20in=20NAT?= =?UTF-8?q?=20mode=20=E2=80=94=20only=20pool=20mode=20needs=20per-VM=20all?= =?UTF-8?q?ocation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In NAT mode, all VMs share a single gateway IP for SNAT. No per-VM public IPs are allocated. Previously, external IPAM was initialized for any external_mode != "", causing noisy AllocateIP failures (empty pool range) on every instance launch. Now IPAM is only initialized when external_mode == "pool". In NAT mode, d.externalIPAM stays nil, cleanly skipping the auto-assign public IP path. SNAT topology is still created by vpcd via the pool's gateway_ip. Part of mulga-737 (Phase 16). --- spinifex/daemon/daemon.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spinifex/daemon/daemon.go b/spinifex/daemon/daemon.go index 8c1a69f8c..7915681da 100644 --- a/spinifex/daemon/daemon.go +++ b/spinifex/daemon/daemon.go @@ -547,8 +547,9 @@ func (d *Daemon) Start() error { return fmt.Errorf("failed to initialize VPC service: %w", err) } - // Initialize external IPAM if external networking is configured - if d.clusterConfig != nil && d.clusterConfig.Network.ExternalMode != "" { + // Initialize external IPAM if pool mode is configured (per-VM public IPs). + // NAT mode only uses SNAT via a shared gateway IP — no per-VM allocation needed. + if d.clusterConfig != nil && d.clusterConfig.Network.ExternalMode == "pool" { js, jsErr := d.natsConn.JetStream() if jsErr != nil { slog.Warn("Failed to get JetStream for external IPAM", "err", jsErr)