Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions pkg/workstation/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,17 @@ func (n *BaseNetworkManager) Initialize() error {

n.services = serviceList

// Create PortAllocator for this initialization run
portAllocator := services.NewPortAllocator()

networkCIDR := n.configHandler.GetString("network.cidr_block")
if networkCIDR == "" {
networkCIDR = constants.DefaultNetworkCIDR
if err := n.configHandler.Set("network.cidr_block", networkCIDR); err != nil {
return fmt.Errorf("error setting default network CIDR: %w", err)
}
}
if err := assignIPAddresses(n.services, &networkCIDR); err != nil {
if err := assignIPAddresses(n.services, &networkCIDR, portAllocator); err != nil {
return fmt.Errorf("error assigning IP addresses: %w", err)
}

Expand All @@ -123,7 +126,7 @@ func (n *BaseNetworkManager) isLocalhostMode() bool {
// =============================================================================

// assignIPAddresses assigns IP addresses to services based on the network CIDR.
var assignIPAddresses = func(services []services.Service, networkCIDR *string) error {
var assignIPAddresses = func(serviceList []services.Service, networkCIDR *string, portAllocator *services.PortAllocator) error {
if networkCIDR == nil || *networkCIDR == "" {
return fmt.Errorf("network CIDR is not defined")
}
Expand All @@ -139,8 +142,9 @@ var assignIPAddresses = func(services []services.Service, networkCIDR *string) e
// Skip the first IP address
ip = incrementIP(ip)

for i := range services {
if err := services[i].SetAddress(ip.String()); err != nil {
for i := range serviceList {
serviceAddress := ip.String()
if err := serviceList[i].SetAddress(serviceAddress, portAllocator); err != nil {
return fmt.Errorf("error setting address for service: %w", err)
}
ip = incrementIP(ip)
Expand Down
28 changes: 14 additions & 14 deletions pkg/workstation/network/network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import (
"testing"

"github.com/windsorcli/cli/pkg/context/config"
"github.com/windsorcli/cli/pkg/di"
"github.com/windsorcli/cli/pkg/context/shell"
"github.com/windsorcli/cli/pkg/context/shell/ssh"
"github.com/windsorcli/cli/pkg/di"
"github.com/windsorcli/cli/pkg/workstation/services"
)

Expand Down Expand Up @@ -251,11 +251,11 @@ func TestNetworkManager_Initialize(t *testing.T) {
var setAddressCalls []string
mockService1 := mocks.Services[0]
mockService2 := mocks.Services[1]
mockService1.SetAddressFunc = func(address string) error {
mockService1.SetAddressFunc = func(address string, portAllocator *services.PortAllocator) error {
setAddressCalls = append(setAddressCalls, address)
return nil
}
mockService2.SetAddressFunc = func(address string) error {
mockService2.SetAddressFunc = func(address string, portAllocator *services.PortAllocator) error {
setAddressCalls = append(setAddressCalls, address)
return nil
}
Expand Down Expand Up @@ -286,7 +286,7 @@ func TestNetworkManager_Initialize(t *testing.T) {
t.Run("SetAddressFailure", func(t *testing.T) {
// Given a network manager with service address failure
manager, mocks := setup(t)
mocks.Services[0].SetAddressFunc = func(address string) error {
mocks.Services[0].SetAddressFunc = func(address string, portAllocator *services.PortAllocator) error {
return fmt.Errorf("mock error setting address for service")
}

Expand Down Expand Up @@ -370,7 +370,7 @@ func TestNetworkManager_Initialize(t *testing.T) {
t.Run("ErrorSettingNetworkCidr", func(t *testing.T) {
// Given a network manager with CIDR setting error
manager, mocks := setup(t)
mocks.Services[0].SetAddressFunc = func(address string) error {
mocks.Services[0].SetAddressFunc = func(address string, portAllocator *services.PortAllocator) error {
return fmt.Errorf("error setting default network CIDR")
}

Expand All @@ -392,7 +392,7 @@ func TestNetworkManager_Initialize(t *testing.T) {
t.Run("ErrorAssigningIPAddresses", func(t *testing.T) {
// Given a network manager with IP assignment error
manager, mocks := setup(t)
mocks.Services[0].SetAddressFunc = func(address string) error {
mocks.Services[0].SetAddressFunc = func(address string, portAllocator *services.PortAllocator) error {
return fmt.Errorf("mock assign IP addresses error")
}

Expand Down Expand Up @@ -477,18 +477,18 @@ func TestNetworkManager_assignIPAddresses(t *testing.T) {
// Given a list of services and a network CIDR
_, mocks := setup(t)
var setAddressCalls []string
mocks.Services[0].SetAddressFunc = func(address string) error {
mocks.Services[0].SetAddressFunc = func(address string, portAllocator *services.PortAllocator) error {
setAddressCalls = append(setAddressCalls, address)
return nil
}
mocks.Services[1].SetAddressFunc = func(address string) error {
mocks.Services[1].SetAddressFunc = func(address string, portAllocator *services.PortAllocator) error {
setAddressCalls = append(setAddressCalls, address)
return nil
}
networkCIDR := "10.5.0.0/16"

// When assigning IP addresses
err := assignIPAddresses(toServices(mocks.Services), &networkCIDR)
err := assignIPAddresses(toServices(mocks.Services), &networkCIDR, services.NewPortAllocator())

// Then no error should occur
if err != nil {
Expand All @@ -510,7 +510,7 @@ func TestNetworkManager_assignIPAddresses(t *testing.T) {
networkCIDR := "invalid-cidr"

// When assigning IP addresses
err := assignIPAddresses(toServices(mocks.Services), &networkCIDR)
err := assignIPAddresses(toServices(mocks.Services), &networkCIDR, services.NewPortAllocator())

// Then an error should occur
if err == nil {
Expand All @@ -526,13 +526,13 @@ func TestNetworkManager_assignIPAddresses(t *testing.T) {
t.Run("ErrorSettingAddress", func(t *testing.T) {
// Given a service that fails to set address
_, mocks := setup(t)
mocks.Services[0].SetAddressFunc = func(address string) error {
mocks.Services[0].SetAddressFunc = func(address string, portAllocator *services.PortAllocator) error {
return fmt.Errorf("error setting address")
}
networkCIDR := "10.5.0.0/16"

// When assigning IP addresses
err := assignIPAddresses(toServices(mocks.Services[:1]), &networkCIDR)
err := assignIPAddresses(toServices(mocks.Services[:1]), &networkCIDR, services.NewPortAllocator())

// Then an error should occur
if err == nil {
Expand All @@ -551,7 +551,7 @@ func TestNetworkManager_assignIPAddresses(t *testing.T) {
networkCIDR := "10.5.0.0/30"

// When assigning IP addresses
err := assignIPAddresses(toServices(mocks.Services), &networkCIDR)
err := assignIPAddresses(toServices(mocks.Services), &networkCIDR, services.NewPortAllocator())

// Then an error should occur
if err == nil {
Expand All @@ -570,7 +570,7 @@ func TestNetworkManager_assignIPAddresses(t *testing.T) {
var networkCIDR *string

// When assigning IP addresses
err := assignIPAddresses(toServices(mocks.Services[:1]), networkCIDR)
err := assignIPAddresses(toServices(mocks.Services[:1]), networkCIDR, services.NewPortAllocator())

// Then an error should occur
if err == nil {
Expand Down
4 changes: 2 additions & 2 deletions pkg/workstation/services/dns_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,12 @@ func (s *DNSService) Initialize() error {
}

// SetAddress updates DNS address in config and calls BaseService's SetAddress.
func (s *DNSService) SetAddress(address string) error {
func (s *DNSService) SetAddress(address string, portAllocator *PortAllocator) error {
err := s.configHandler.Set("dns.address", address)
if err != nil {
return fmt.Errorf("error setting DNS address: %w", err)
}
return s.BaseService.SetAddress(address)
return s.BaseService.SetAddress(address, portAllocator)
}

// GetComposeConfig sets up CoreDNS with context and domain, configures ports if localhost.
Expand Down
12 changes: 6 additions & 6 deletions pkg/workstation/services/dns_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ func TestDNSService_SetAddress(t *testing.T) {

// When SetAddress is called
address := "127.0.0.1"
err := service.SetAddress(address)
err := service.SetAddress(address, nil)

setAddress := mocks.ConfigHandler.GetString("dns.address")

Expand Down Expand Up @@ -180,7 +180,7 @@ func TestDNSService_SetAddress(t *testing.T) {

// When SetAddress is called
address := "127.0.0.1"
err := service.SetAddress(address)
err := service.SetAddress(address, nil)

// Then an error should be returned
if err == nil {
Expand Down Expand Up @@ -329,7 +329,7 @@ func TestDNSService_WriteConfig(t *testing.T) {
service, mocks := setup(t)

// Set the address to localhost to mock IsLocalhost behavior
service.SetAddress("127.0.0.1")
service.SetAddress("127.0.0.1", nil)

// Set the DNS domain
mocks.ConfigHandler.Set("dns.domain", "test")
Expand Down Expand Up @@ -384,7 +384,7 @@ func TestDNSService_WriteConfig(t *testing.T) {
}

service.SetName("test")
service.SetAddress("192.168.1.1")
service.SetAddress("192.168.1.1", nil)

// Execute
err := service.WriteConfig()
Expand Down Expand Up @@ -643,7 +643,7 @@ func TestDNSService_WriteConfig(t *testing.T) {
}

service.SetName("test")
service.SetAddress("192.168.1.1")
service.SetAddress("192.168.1.1", nil)

// Execute
err := service.WriteConfig()
Expand Down Expand Up @@ -840,7 +840,7 @@ func TestDNSService_GetHostname(t *testing.T) {
t.Run("ErrorGettingHostname", func(t *testing.T) {
// Given a DNSService with no name set
service, mocks := setup(t)
service.SetName("") // Clear the name
service.SetName("") // Clear the name
mocks.ConfigHandler.Set("dns.domain", "") // Clear the domain

// When GetHostname is called
Expand Down
6 changes: 3 additions & 3 deletions pkg/workstation/services/mock_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type MockService struct {
BaseService
GetComposeConfigFunc func() (*types.Config, error)
WriteConfigFunc func() error
SetAddressFunc func(address string) error
SetAddressFunc func(address string, portAllocator *PortAllocator) error
GetAddressFunc func() string
InitializeFunc func() error
SetNameFunc func(name string)
Expand Down Expand Up @@ -65,9 +65,9 @@ func (m *MockService) WriteConfig() error {
}

// SetAddress calls the mock SetAddressFunc if it is set, otherwise returns nil
func (m *MockService) SetAddress(address string) error {
func (m *MockService) SetAddress(address string, portAllocator *PortAllocator) error {
if m.SetAddressFunc != nil {
return m.SetAddressFunc(address)
return m.SetAddressFunc(address, portAllocator)
}
return nil
}
Expand Down
6 changes: 3 additions & 3 deletions pkg/workstation/services/mock_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,12 @@ func TestMockService_SetAddress(t *testing.T) {
t.Run("Success", func(t *testing.T) {
// Given a new MockService with SetAddressFunc set
mock := NewMockService()
mock.SetAddressFunc = func(address string) error {
mock.SetAddressFunc = func(address string, portAllocator *PortAllocator) error {
return nil
}

// When SetAddress is called
err := mock.SetAddress("test-address")
err := mock.SetAddress("test-address", nil)

// Then no error should be returned
if err != nil {
Expand All @@ -136,7 +136,7 @@ func TestMockService_SetAddress(t *testing.T) {
mock := NewMockService()

// When SetAddress is called
err := mock.SetAddress("test-address")
err := mock.SetAddress("test-address", nil)

// Then no error should be returned
if err != nil {
Expand Down
25 changes: 25 additions & 0 deletions pkg/workstation/services/port_allocator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package services

// PortAllocator manages port allocation for services during network initialization.
// It tracks allocated ports to prevent conflicts.
type PortAllocator struct {
allocatedPorts map[int]bool
}

// NewPortAllocator creates a new PortAllocator with initial state.
func NewPortAllocator() *PortAllocator {
return &PortAllocator{
allocatedPorts: make(map[int]bool),
}
}

// NextAvailablePort finds the next available port starting from basePort. If basePort is already allocated,
// it increments until finding an available port. Returns the allocated port.
func (p *PortAllocator) NextAvailablePort(basePort int) int {
port := basePort
for p.allocatedPorts[port] {
port++
}
p.allocatedPorts[port] = true
return port
}
4 changes: 2 additions & 2 deletions pkg/workstation/services/registry_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ func (s *RegistryService) GetComposeConfig() (*types.Config, error) {

// SetAddress configures the registry's address, forms a hostname, and updates the registry config.
// It assigns the "registry_url" and the default host port for the first non-remote registry, storing it as "localRegistry".
func (s *RegistryService) SetAddress(address string) error {
if err := s.BaseService.SetAddress(address); err != nil {
func (s *RegistryService) SetAddress(address string, portAllocator *PortAllocator) error {
if err := s.BaseService.SetAddress(address, portAllocator); err != nil {
return fmt.Errorf("failed to set address for base service: %w", err)
}

Expand Down
18 changes: 9 additions & 9 deletions pkg/workstation/services/registry_service_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ contexts:
}

// When SetAddress is called with localhost
err := service.SetAddress("localhost")
err := service.SetAddress("localhost", nil)

// Then there should be no error
if err != nil {
Expand Down Expand Up @@ -303,7 +303,7 @@ contexts:
}

// When SetAddress is called
err := service.SetAddress("192.168.1.1")
err := service.SetAddress("192.168.1.1", nil)

// Then there should be no error
if err != nil {
Expand Down Expand Up @@ -340,7 +340,7 @@ contexts:
}

// When SetAddress is called
err := service.SetAddress("192.168.1.1")
err := service.SetAddress("192.168.1.1", nil)

// Then there should be no error
if err != nil {
Expand All @@ -366,7 +366,7 @@ contexts:
service1.SetName("registry1")

// When SetAddress is called for first registry
err := service1.SetAddress("localhost")
err := service1.SetAddress("localhost", nil)
if err != nil {
t.Fatalf("Failed to set address for first registry: %v", err)
}
Expand All @@ -378,7 +378,7 @@ contexts:
service2.SetName("registry2")

// When SetAddress is called for second registry
err = service2.SetAddress("localhost")
err = service2.SetAddress("localhost", nil)
if err != nil {
t.Fatalf("Failed to set address for second registry: %v", err)
}
Expand Down Expand Up @@ -411,7 +411,7 @@ contexts:
service.SetName("registry")

// When SetAddress is called with invalid address
err := service.SetAddress("invalid-address")
err := service.SetAddress("invalid-address", nil)

// Then there should be an error
if err == nil {
Expand Down Expand Up @@ -440,7 +440,7 @@ contexts:
}

// When SetAddress is called
err := service.SetAddress("localhost")
err := service.SetAddress("localhost", nil)

// Then there should be an error
if err == nil {
Expand Down Expand Up @@ -492,7 +492,7 @@ contexts:
}

// When SetAddress is called
err := service.SetAddress("localhost")
err := service.SetAddress("localhost", nil)

// Then there should be an error
if err == nil {
Expand Down Expand Up @@ -548,7 +548,7 @@ contexts:
}

// When SetAddress is called
err := service.SetAddress("localhost")
err := service.SetAddress("localhost", nil)

// Then there should be an error
if err == nil {
Expand Down
Loading
Loading