@@ -436,13 +436,17 @@ func (n *Node) AllocateIPs(ctx context.Context, a *ipam.AllocationAction) error
436436func (n * Node ) AllocateStaticIP (ctx context.Context , staticIPTags ipamTypes.Tags ) (string , error ) {
437437 n .mutex .RLock ()
438438 defer n .mutex .RUnlock ()
439+
439440 for _ , eni := range n .enis {
440- if eni .PublicIP == "" {
441+ if eni .Number == 0 {
442+ if eni .PublicIP != "" {
443+ return eni .PublicIP , nil
444+ }
441445 return n .manager .ec2api .AssociateEIP (ctx , eni .ID , staticIPTags )
442446 }
443447 }
444448
445- return "" , fmt .Errorf ("no ENI found to associate static IP " )
449+ return "" , fmt .Errorf ("no primary ENI found" )
446450}
447451
448452func (n * Node ) getSecurityGroupIDs (ctx context.Context , eniSpec eniTypes.ENISpec ) ([]string , error ) {
@@ -741,6 +745,12 @@ func (n *Node) ResyncInterfacesAndIPs(ctx context.Context, scopedLog *slog.Logge
741745
742746 n .enis [e .ID ] = * e
743747
748+ // Check for public IP on primary ENI before exclusion logic
749+ // The primary ENI may be excluded from IPAM but we still need to track its public IP
750+ if e .Number == 0 && e .PublicIP != "" {
751+ stats .AssignedStaticIP = e .PublicIP
752+ }
753+
744754 // 3. Finally, we iterate any already existing interfaces and add on any extra
745755 // capacity to account for leftover prefix delegated /28 ip slots.
746756 leftoverPrefixCapcity , effectiveLimits := n .getEffectiveIPLimits (e , limits .IPv4 )
@@ -762,11 +772,6 @@ func (n *Node) ResyncInterfacesAndIPs(ctx context.Context, scopedLog *slog.Logge
762772 available [ip ] = ipamTypes.AllocationIP {Resource : e .ID }
763773 }
764774
765- // If the primary ENI has a public IP, we store it
766- if e .Number == 0 && e .PublicIP != "" {
767- stats .AssignedStaticIP = e .PublicIP
768- }
769-
770775 return nil
771776 })
772777 enis := len (n .enis )
0 commit comments