From b7505f8b5fcd676996f6158a9316c8d16b31377d Mon Sep 17 00:00:00 2001 From: joshsiv-mulga Date: Sun, 24 May 2026 20:10:49 +1000 Subject: [PATCH] fix(igw): write attachment State="attached" for AWS parity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reconciler intent loader (network/reconcile/intent.go::loadIGWs) filters IGW records with `State == "attached"`, but AttachInternetGateway was writing `State = "available"`. The reconciler therefore never picked up any attached IGW — `intent_igws=0` on every pass — so the OVN external switch + gateway LRP + WAN bridge wiring built by IGWManager.AttachIGW never ran for default-VPC IGWs (whose live `vpc.igw-attach` publish at daemon bootstrap is lost — vpcd subscriber not yet wired). Net effect on single-node e2e: every SSH probe to 192.168.x public IPs timed out (TestSSHProbe, TestModifyInstanceAttribute, TestRebootInstance, TestNATGateway, TestSGToSGDatapath) because SNAT/DNAT rules on the VPC router had no path to the external network. Match AWS InternetGatewayAttachment.State semantics: - Attach: State="attached" - Detach: State="detached" Detach value is internal — recordToEC2 gates Attachments on VpcId != "", so the detached State is never surfaced to API consumers. Bead: mulga-siv-131 --- spinifex/handlers/ec2/igw/service_impl.go | 4 ++-- spinifex/handlers/ec2/igw/service_impl_test.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spinifex/handlers/ec2/igw/service_impl.go b/spinifex/handlers/ec2/igw/service_impl.go index 52b7f7a17..7223a83fb 100644 --- a/spinifex/handlers/ec2/igw/service_impl.go +++ b/spinifex/handlers/ec2/igw/service_impl.go @@ -291,7 +291,7 @@ func (s *IGWServiceImpl) AttachInternetGateway(input *ec2.AttachInternetGatewayI } record.VpcId = vpcID - record.State = "available" + record.State = "attached" data, err := json.Marshal(record) if err != nil { @@ -349,7 +349,7 @@ func (s *IGWServiceImpl) DetachInternetGateway(input *ec2.DetachInternetGatewayI } record.VpcId = "" - record.State = "available" + record.State = "detached" data, err := json.Marshal(record) if err != nil { diff --git a/spinifex/handlers/ec2/igw/service_impl_test.go b/spinifex/handlers/ec2/igw/service_impl_test.go index b01e55887..ef21eef3a 100644 --- a/spinifex/handlers/ec2/igw/service_impl_test.go +++ b/spinifex/handlers/ec2/igw/service_impl_test.go @@ -191,7 +191,7 @@ func TestAttachInternetGateway(t *testing.T) { require.Len(t, desc.InternetGateways, 1) require.Len(t, desc.InternetGateways[0].Attachments, 1) assert.Equal(t, "vpc-test123", *desc.InternetGateways[0].Attachments[0].VpcId) - assert.Equal(t, "available", *desc.InternetGateways[0].Attachments[0].State) + assert.Equal(t, "attached", *desc.InternetGateways[0].Attachments[0].State) } func TestAttachInternetGateway_NotFound(t *testing.T) { @@ -527,7 +527,7 @@ func TestDescribeInternetGateways_FilterByAttachmentState(t *testing.T) { desc, err := svc.DescribeInternetGateways(&ec2.DescribeInternetGatewaysInput{ Filters: []*ec2.Filter{ - {Name: aws.String("attachment.state"), Values: []*string{aws.String("available")}}, + {Name: aws.String("attachment.state"), Values: []*string{aws.String("attached")}}, }, }, testAccountID) require.NoError(t, err)