diff --git a/cmd/spinifex/cmd/admin.go b/cmd/spinifex/cmd/admin.go index e342fcc8a..e0de62fe0 100644 --- a/cmd/spinifex/cmd/admin.go +++ b/cmd/spinifex/cmd/admin.go @@ -837,12 +837,12 @@ func runAdminInit(cmd *cobra.Command, args []string) { OVNNBAddr: "tcp:127.0.0.1:6641", OVNSBAddr: "tcp:127.0.0.1:6642", - ExternalMode: externalMode, - ExternalIface: externalIface, - ExternalDHCP: useExternalDHCP, - PoolName: "wan", - PoolStart: poolStart, - PoolEnd: poolEnd, + ExternalMode: externalMode, + ExternalIface: externalIface, + ExternalDHCP: useExternalDHCP, + PoolName: "wan", + PoolStart: poolStart, + PoolEnd: poolEnd, PoolGateway: externalGateway, PoolPrefixLen: externalPrefixLen, PoolDNSServers: dnsServers, @@ -1721,7 +1721,7 @@ func detectDNSServers(iface string) []string { data, err := os.ReadFile("/etc/resolv.conf") if err == nil { var servers []string - for _, line := range strings.Split(string(data), "\n") { + for line := range strings.SplitSeq(string(data), "\n") { line = strings.TrimSpace(line) if strings.HasPrefix(line, "nameserver ") { ip := strings.TrimSpace(strings.TrimPrefix(line, "nameserver")) @@ -1747,14 +1747,14 @@ func detectDNSServers(iface string) []string { // Format: "Link 2 (enp0s3): 192.168.1.1 8.8.8.8 1.1.1.1" func parseDNSFromResolvectl(output string) []string { var servers []string - for _, line := range strings.Split(output, "\n") { + for line := range strings.SplitSeq(output, "\n") { // Find the colon separator, IPs come after it - idx := strings.Index(line, ":") - if idx < 0 { + _, after, ok := strings.Cut(line, ":") + if !ok { continue } - fields := strings.Fields(line[idx+1:]) - for _, f := range fields { + fields := strings.FieldsSeq(after) + for f := range fields { if net.ParseIP(f) != nil && f != "127.0.0.53" && f != "127.0.0.1" { servers = append(servers, f) } diff --git a/spinifex/admin/admin.go b/spinifex/admin/admin.go index c51199d4f..57e8c6549 100644 --- a/spinifex/admin/admin.go +++ b/spinifex/admin/admin.go @@ -65,16 +65,16 @@ type ConfigSettings struct { OVNSBAddr string // External networking for public subnets - ExternalMode string // "pool", "nat", or "" (disabled) - ExternalIface string // WAN NIC name (e.g., "eth0", "eth1") - ExternalDHCP bool // Obtain gateway IP via DHCP on macvlan/bridge - PoolName string // External pool name (e.g., "wan") - PoolStart string // First IP in external pool range - PoolEnd string // Last IP in external pool range - PoolGateway string // WAN gateway IP - PoolGatewayIP string // Explicit SNAT IP (for nat mode without DHCP) - PoolPrefixLen int // Subnet prefix length (default 24) - PoolDNSServers []string // DNS servers for VM DHCP (auto-detected from host) + ExternalMode string // "pool", "nat", or "" (disabled) + ExternalIface string // WAN NIC name (e.g., "eth0", "eth1") + ExternalDHCP bool // Obtain gateway IP via DHCP on macvlan/bridge + PoolName string // External pool name (e.g., "wan") + PoolStart string // First IP in external pool range + PoolEnd string // Last IP in external pool range + PoolGateway string // WAN gateway IP + PoolGatewayIP string // Explicit SNAT IP (for nat mode without DHCP) + PoolPrefixLen int // Subnet prefix length (default 24) + PoolDNSServers []string // DNS servers for VM DHCP (auto-detected from host) // Other nodes in the cluster (for config source of truth) RemoteNodes []RemoteNode diff --git a/spinifex/admin/network_detect.go b/spinifex/admin/network_detect.go index 23d9f7cc7..865c2649d 100644 --- a/spinifex/admin/network_detect.go +++ b/spinifex/admin/network_detect.go @@ -5,6 +5,8 @@ import ( "net" "os/exec" "strings" + + "github.com/mulgadc/spinifex/spinifex/utils" ) // DetectedInterface represents a network interface discovered on the host. @@ -62,7 +64,7 @@ func DetectNetwork() (*DetectedNetwork, error) { seen := make(map[string]bool) var interfaces []DetectedInterface - for _, line := range strings.Split(strings.TrimSpace(string(allRoutes)), "\n") { + for line := range strings.SplitSeq(strings.TrimSpace(string(allRoutes)), "\n") { if line == "" { continue } @@ -169,10 +171,10 @@ func SuggestPoolRange(wan *DetectedInterface) (start, end string) { for i := 3; i >= 0 && carry > 0; i-- { val := int(startIP[i]) - carry if val < 0 { - startIP[i] = byte(256 + val) + startIP[i] = utils.SafeIntToUint8(256 + val) carry = 1 } else { - startIP[i] = byte(val) + startIP[i] = utils.SafeIntToUint8(val) carry = 0 } } diff --git a/spinifex/daemon/daemon.go b/spinifex/daemon/daemon.go index 8c1a69f8c..c566bf28d 100644 --- a/spinifex/daemon/daemon.go +++ b/spinifex/daemon/daemon.go @@ -32,8 +32,8 @@ import ( "github.com/mulgadc/spinifex/spinifex/awserrors" "github.com/mulgadc/spinifex/spinifex/config" handlers_ec2_account "github.com/mulgadc/spinifex/spinifex/handlers/ec2/account" - handlers_ec2_eip "github.com/mulgadc/spinifex/spinifex/handlers/ec2/eip" handlers_ec2_eigw "github.com/mulgadc/spinifex/spinifex/handlers/ec2/eigw" + handlers_ec2_eip "github.com/mulgadc/spinifex/spinifex/handlers/ec2/eip" handlers_ec2_igw "github.com/mulgadc/spinifex/spinifex/handlers/ec2/igw" handlers_ec2_image "github.com/mulgadc/spinifex/spinifex/handlers/ec2/image" handlers_ec2_instance "github.com/mulgadc/spinifex/spinifex/handlers/ec2/instance" diff --git a/spinifex/daemon/daemon_handlers_vpc.go b/spinifex/daemon/daemon_handlers_vpc.go index fdf552984..7d1c983c4 100644 --- a/spinifex/daemon/daemon_handlers_vpc.go +++ b/spinifex/daemon/daemon_handlers_vpc.go @@ -188,4 +188,3 @@ func (d *Daemon) ensureDefaultVPCInfrastructure() { } } } - diff --git a/spinifex/gateway/ec2.go b/spinifex/gateway/ec2.go index c779ae49d..263854c19 100644 --- a/spinifex/gateway/ec2.go +++ b/spinifex/gateway/ec2.go @@ -14,6 +14,7 @@ import ( "github.com/mulgadc/spinifex/spinifex/awserrors" gateway_ec2_account "github.com/mulgadc/spinifex/spinifex/gateway/ec2/account" gateway_ec2_eigw "github.com/mulgadc/spinifex/spinifex/gateway/ec2/eigw" + gateway_ec2_eip "github.com/mulgadc/spinifex/spinifex/gateway/ec2/eip" gateway_ec2_igw "github.com/mulgadc/spinifex/spinifex/gateway/ec2/igw" gateway_ec2_image "github.com/mulgadc/spinifex/spinifex/gateway/ec2/image" gateway_ec2_instance "github.com/mulgadc/spinifex/spinifex/gateway/ec2/instance" @@ -22,7 +23,6 @@ import ( gateway_ec2_snapshot "github.com/mulgadc/spinifex/spinifex/gateway/ec2/snapshot" gateway_ec2_tags "github.com/mulgadc/spinifex/spinifex/gateway/ec2/tags" gateway_ec2_volume "github.com/mulgadc/spinifex/spinifex/gateway/ec2/volume" - gateway_ec2_eip "github.com/mulgadc/spinifex/spinifex/gateway/ec2/eip" gateway_ec2_vpc "github.com/mulgadc/spinifex/spinifex/gateway/ec2/vpc" gateway_ec2_zone "github.com/mulgadc/spinifex/spinifex/gateway/ec2/zone" "github.com/mulgadc/spinifex/spinifex/utils" diff --git a/spinifex/handlers/ec2/igw/service_impl.go b/spinifex/handlers/ec2/igw/service_impl.go index 29d6e1417..a18b8ff4c 100644 --- a/spinifex/handlers/ec2/igw/service_impl.go +++ b/spinifex/handlers/ec2/igw/service_impl.go @@ -87,7 +87,6 @@ func (s *IGWServiceImpl) CreateInternetGateway(input *ec2.CreateInternetGatewayI } func (s *IGWServiceImpl) createIGW(input *ec2.CreateInternetGatewayInput, accountID, igwID string) (*ec2.CreateInternetGatewayOutput, error) { - record := IGWRecord{ InternetGatewayId: igwID, State: "available", diff --git a/spinifex/handlers/ec2/vpc/external_ipam.go b/spinifex/handlers/ec2/vpc/external_ipam.go index e2bfaa7b7..948b4e580 100644 --- a/spinifex/handlers/ec2/vpc/external_ipam.go +++ b/spinifex/handlers/ec2/vpc/external_ipam.go @@ -21,7 +21,7 @@ const ( type ExternalIPAllocation struct { Type string `json:"type"` // "gateway", "auto_assign", "elastic_ip" AllocationID string `json:"allocation_id,omitempty"` // For elastic IPs - Association string `json:"association,omitempty"` // ENI ID for elastic IPs + Association string `json:"association,omitempty"` // ENI ID for elastic IPs ENIId string `json:"eni_id,omitempty"` // ENI owning this IP InstanceId string `json:"instance_id,omitempty"` // Instance owning this IP Note string `json:"note,omitempty"` // Human-readable note diff --git a/spinifex/handlers/ec2/vpc/security_group.go b/spinifex/handlers/ec2/vpc/security_group.go index a1d1018ef..119bffa70 100644 --- a/spinifex/handlers/ec2/vpc/security_group.go +++ b/spinifex/handlers/ec2/vpc/security_group.go @@ -450,12 +450,12 @@ func (s *VPCServiceImpl) RevokeSecurityGroupEgress(input *ec2.RevokeSecurityGrou // sgRecordToEC2 converts a SecurityGroupRecord to an EC2 SecurityGroup. func (s *VPCServiceImpl) sgRecordToEC2(record *SecurityGroupRecord, accountID string) *ec2.SecurityGroup { sg := &ec2.SecurityGroup{ - GroupId: aws.String(record.GroupId), - GroupName: aws.String(record.GroupName), - Description: aws.String(record.Description), - VpcId: aws.String(record.VpcId), - OwnerId: aws.String(accountID), - IpPermissions: sgRulesToIpPermissions(record.IngressRules), + GroupId: aws.String(record.GroupId), + GroupName: aws.String(record.GroupName), + Description: aws.String(record.Description), + VpcId: aws.String(record.VpcId), + OwnerId: aws.String(accountID), + IpPermissions: sgRulesToIpPermissions(record.IngressRules), IpPermissionsEgress: sgRulesToIpPermissions(record.EgressRules), } diff --git a/spinifex/handlers/iam/service_impl.go b/spinifex/handlers/iam/service_impl.go index dffbc8ae1..e31769d7f 100644 --- a/spinifex/handlers/iam/service_impl.go +++ b/spinifex/handlers/iam/service_impl.go @@ -731,10 +731,14 @@ func (s *IAMServiceImpl) seedAdminAccount(admin *AdminBootstrapData) error { // this account. Without this, the admin account has no default VPC/subnet // and the user must create one manually. if s.natsConn != nil { - evt, _ := json.Marshal(struct { + evt, err := json.Marshal(struct { AccountID string `json:"account_id"` AccountName string `json:"account_name"` }{AccountID: admin.AccountID, AccountName: admin.AccountName}) + if err != nil { + slog.Warn("Failed to marshal account creation event", "accountID", admin.AccountID, "error", err) + return nil + } if err := s.natsConn.Publish("iam.account.created", evt); err != nil { slog.Warn("Failed to publish account creation event for admin account", "accountID", admin.AccountID, "error", err) } diff --git a/spinifex/services/vpcd/nbdb/model.go b/spinifex/services/vpcd/nbdb/model.go index 08551e848..a98eade4d 100644 --- a/spinifex/services/vpcd/nbdb/model.go +++ b/spinifex/services/vpcd/nbdb/model.go @@ -96,8 +96,8 @@ type LogicalRouterStaticRoute struct { type PortGroup struct { UUID string `ovsdb:"_uuid"` Name string `ovsdb:"name"` - Ports []string `ovsdb:"ports"` // UUIDs of logical switch ports - ACLs []string `ovsdb:"acls"` // UUIDs of ACLs + Ports []string `ovsdb:"ports"` // UUIDs of logical switch ports + ACLs []string `ovsdb:"acls"` // UUIDs of ACLs ExternalIDs map[string]string `ovsdb:"external_ids"` } diff --git a/spinifex/services/vpcd/reconcile.go b/spinifex/services/vpcd/reconcile.go index 3cc20252f..6b7ea7f12 100644 --- a/spinifex/services/vpcd/reconcile.go +++ b/spinifex/services/vpcd/reconcile.go @@ -7,7 +7,7 @@ import ( // ReconcileResult tracks what was created during reconciliation. type ReconcileResult struct { - RoutersCreated int + RoutersCreated int SwitchesCreated int IGWsCreated int } diff --git a/spinifex/services/vpcd/reconcile_test.go b/spinifex/services/vpcd/reconcile_test.go index 1b0d6d6e0..1074a88f4 100644 --- a/spinifex/services/vpcd/reconcile_test.go +++ b/spinifex/services/vpcd/reconcile_test.go @@ -33,7 +33,7 @@ func TestReconcile_CreatesBootstrapTopology(t *testing.T) { _ = ovn.Connect(context.Background()) topo := NewTopologyHandler(ovn, WithExternalNetwork("pool", []ExternalPoolConfig{{ - Name: "wan", + Name: "wan", RangeStart: "192.168.1.200", RangeEnd: "192.168.1.250", Gateway: "192.168.1.1", diff --git a/spinifex/services/vpcd/topology.go b/spinifex/services/vpcd/topology.go index 5dff86f3c..6eca46c08 100644 --- a/spinifex/services/vpcd/topology.go +++ b/spinifex/services/vpcd/topology.go @@ -624,7 +624,6 @@ func (h *TopologyHandler) handleIGWAttach(msg *nats.Msg) { gatewayIP := "169.254.0.1" gatewayNetwork := "169.254.0.1/30" wanGateway := "169.254.0.2" - prefixLen := 30 if pool != nil { gip := pool.GatewayIP @@ -632,7 +631,7 @@ func (h *TopologyHandler) handleIGWAttach(msg *nats.Msg) { gip = pool.RangeStart // Default: first IP in range } gatewayIP = gip - prefixLen = pool.PrefixLen + prefixLen := pool.PrefixLen if prefixLen == 0 { prefixLen = 24 } @@ -728,10 +727,9 @@ func (h *TopologyHandler) handleIGWAttach(msg *nats.Msg) { // 7. Schedule gateway chassis for HA — tells OVN which hosts can handle external traffic if len(h.chassisNames) > 0 { for i, chassis := range h.chassisNames { - priority := 20 - (i * 5) // First chassis gets highest priority - if priority < 1 { - priority = 1 - } + priority := max( + // First chassis gets highest priority + 20-(i*5), 1) if err := h.ovn.SetGatewayChassis(ctx, gwPortName, chassis, priority); err != nil { slog.Warn("vpcd: failed to set gateway chassis", "port", gwPortName, "chassis", chassis, "priority", priority, "err", err) } else { @@ -1020,7 +1018,6 @@ func (h *TopologyHandler) reconcileIGW(ctx context.Context, vpcId, igwId string) gatewayIP := "169.254.0.1" gatewayNetwork := "169.254.0.1/30" wanGateway := "169.254.0.2" - prefixLen := 30 if pool != nil { gip := pool.GatewayIP @@ -1028,7 +1025,7 @@ func (h *TopologyHandler) reconcileIGW(ctx context.Context, vpcId, igwId string) gip = pool.RangeStart } gatewayIP = gip - prefixLen = pool.PrefixLen + prefixLen := pool.PrefixLen if prefixLen == 0 { prefixLen = 24 } @@ -1140,10 +1137,7 @@ func (h *TopologyHandler) reconcileIGW(ctx context.Context, vpcId, igwId string) // 7. Schedule gateway chassis for i, chassis := range h.chassisNames { - priority := 20 - (i * 5) - if priority < 1 { - priority = 1 - } + priority := max(20-(i*5), 1) if err := h.ovn.SetGatewayChassis(ctx, gwPortName, chassis, priority); err != nil { slog.Warn("vpcd reconcile: failed to set gateway chassis", "chassis", chassis, "err", err) }