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
11 changes: 10 additions & 1 deletion pkg/network/darwin_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,16 @@ func (n *BaseNetworkManager) ConfigureDNS() error {
if tld == "" {
return fmt.Errorf("DNS domain is not configured")
}
dnsIP := n.configHandler.GetString("dns.address")

var dnsIP string
if n.isLocalhostMode() {
dnsIP = "127.0.0.1"
} else {
dnsIP = n.configHandler.GetString("dns.address")
if dnsIP == "" {
return fmt.Errorf("DNS address is not configured")
}
}

resolverDir := "/etc/resolver"
resolverFile := fmt.Sprintf("%s/%s", resolverDir, tld)
Expand Down
64 changes: 61 additions & 3 deletions pkg/network/darwin_network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,14 +360,22 @@ func TestDarwinNetworkManager_ConfigureDNS(t *testing.T) {
}
})

t.Run("SuccessLocalhost", func(t *testing.T) {
t.Run("SuccessLocalhostMode", func(t *testing.T) {
mocks := setupDarwinNetworkManagerMocks()

// Mock the config handler to return docker-desktop for vm.driver
mocks.MockConfigHandler.GetStringFunc = func(key string, defaultValue ...string) string {
if key == "vm.driver" {
switch key {
case "vm.driver":
return "docker-desktop"
case "dns.domain":
return "example.com"
default:
if len(defaultValue) > 0 {
return defaultValue[0]
}
return ""
}
return "some_value"
}

nm := NewBaseNetworkManager(mocks.Injector)
Expand All @@ -377,10 +385,23 @@ func TestDarwinNetworkManager_ConfigureDNS(t *testing.T) {
t.Fatalf("expected no error during initialization, got %v", err)
}

// Mock the writeFile function to capture the content
var capturedContent []byte
writeFile = func(_ string, content []byte, _ os.FileMode) error {
capturedContent = content
return nil
}

err = nm.ConfigureDNS()
if err != nil {
t.Fatalf("expected no error, got %v", err)
}

// Verify that the resolver file contains 127.0.0.1
expectedContent := "nameserver 127.0.0.1\n"
if string(capturedContent) != expectedContent {
t.Errorf("expected resolver file content to be %q, got %q", expectedContent, string(capturedContent))
}
})

t.Run("NoDNSDomainConfigured", func(t *testing.T) {
Expand Down Expand Up @@ -410,6 +431,43 @@ func TestDarwinNetworkManager_ConfigureDNS(t *testing.T) {
}
})

t.Run("NoDNSAddressConfigured", func(t *testing.T) {
mocks := setupDarwinNetworkManagerMocks()

// Mock the config handler to return empty DNS address but valid domain
mocks.MockConfigHandler.GetStringFunc = func(key string, defaultValue ...string) string {
switch key {
case "dns.domain":
return "example.com"
case "dns.address":
return ""
case "vm.driver":
return "lima" // Not localhost mode
default:
if len(defaultValue) > 0 {
return defaultValue[0]
}
return ""
}
}

nm := NewBaseNetworkManager(mocks.Injector)

err := nm.Initialize()
if err != nil {
t.Fatalf("expected no error during initialization, got %v", err)
}

err = nm.ConfigureDNS()
if err == nil {
t.Fatalf("expected error, got nil")
}
expectedError := "DNS address is not configured"
if err.Error() != expectedError {
t.Fatalf("expected error %q, got %q", expectedError, err.Error())
}
})

t.Run("ResolverFileAlreadyExists", func(t *testing.T) {
mocks := setupDarwinNetworkManagerMocks()

Expand Down
11 changes: 10 additions & 1 deletion pkg/network/linux_network.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,16 @@ func (n *BaseNetworkManager) ConfigureDNS() error {
if tld == "" {
return fmt.Errorf("DNS domain is not configured")
}
dnsIP := n.configHandler.GetString("dns.address")

var dnsIP string
if n.isLocalhostMode() {
dnsIP = "127.0.0.1"
} else {
dnsIP = n.configHandler.GetString("dns.address")
if dnsIP == "" {
return fmt.Errorf("DNS address is not configured")
}
}

// If DNS address is configured, use systemd-resolved
resolvConf, err := readLink("/etc/resolv.conf")
Expand Down
123 changes: 123 additions & 0 deletions pkg/network/linux_network_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package network
import (
"fmt"
"net"
"os"
"strings"
"testing"

Expand Down Expand Up @@ -338,6 +339,83 @@ func TestLinuxNetworkManager_ConfigureDNS(t *testing.T) {
}
})

t.Run("SuccessLocalhostMode", func(t *testing.T) {
mocks := setupLinuxNetworkManagerMocks()

// Mock the config handler to return docker-desktop for vm.driver
mocks.MockConfigHandler.GetStringFunc = func(key string, defaultValue ...string) string {
switch key {
case "vm.driver":
return "docker-desktop"
case "dns.domain":
return "example.com"
default:
if len(defaultValue) > 0 {
return defaultValue[0]
}
return ""
}
}

// Mock the readLink function to simulate systemd-resolved being in use
originalReadLink := readLink
defer func() { readLink = originalReadLink }()
readLink = func(_ string) (string, error) {
return "../run/systemd/resolve/stub-resolv.conf", nil
}

// Mock the readFile function to capture the content
var capturedContent []byte
originalReadFile := readFile
defer func() { readFile = originalReadFile }()
readFile = func(_ string) ([]byte, error) {
if capturedContent != nil {
return capturedContent, nil
}
return nil, os.ErrNotExist
}

// Create a networkManager using NewBaseNetworkManager with the mock DI container
nm := NewBaseNetworkManager(mocks.Injector)
err := nm.Initialize()
if err != nil {
t.Fatalf("expected no error during initialization, got %v", err)
}

// Mock the shell.ExecSudo function to capture the content
mocks.MockShell.ExecSudoFunc = func(description, command string, args ...string) (string, error) {
if command == "bash" && args[0] == "-c" {
// Extract the content from the echo command
cmdStr := args[1]

// The command is in the format: echo '[Resolve]\nDNS=127.0.0.1\n' | sudo tee /etc/systemd/resolved.conf.d/dns-override-example.com.con
// We need to extract the content between the first and last single quote before the pipe
if strings.Contains(cmdStr, "echo '") && strings.Contains(cmdStr, "' | sudo tee") {
start := strings.Index(cmdStr, "echo '") + 6
end := strings.Index(cmdStr, "' | sudo tee")
if start < end {
content := cmdStr[start:end]
capturedContent = []byte(content)
}
}
return "", nil
}
return "", nil
}

// Call the ConfigureDNS method
err = nm.ConfigureDNS()
if err != nil {
t.Fatalf("expected no error, got %v", err)
}

// Verify that the drop-in file contains 127.0.0.1
expectedContent := "[Resolve]\nDNS=127.0.0.1\n"
if string(capturedContent) != expectedContent {
t.Errorf("expected drop-in file content to be %q, got %q", expectedContent, string(capturedContent))
}
})

t.Run("domainNotConfigured", func(t *testing.T) {
mocks := setupLinuxNetworkManagerMocks()

Expand Down Expand Up @@ -367,6 +445,51 @@ func TestLinuxNetworkManager_ConfigureDNS(t *testing.T) {
}
})

t.Run("NoDNSAddressConfigured", func(t *testing.T) {
mocks := setupLinuxNetworkManagerMocks()

// Mock the config handler to return empty DNS address but valid domain
mocks.MockConfigHandler.GetStringFunc = func(key string, defaultValue ...string) string {
switch key {
case "dns.domain":
return "example.com"
case "dns.address":
return ""
case "vm.driver":
return "lima" // Not localhost mode
default:
if len(defaultValue) > 0 {
return defaultValue[0]
}
return ""
}
}

// Mock the readLink function to simulate systemd-resolved being in use
originalReadLink := readLink
defer func() { readLink = originalReadLink }()
readLink = func(_ string) (string, error) {
return "../run/systemd/resolve/stub-resolv.conf", nil
}

// Create a networkManager using NewBaseNetworkManager with the mock DI container
nm := NewBaseNetworkManager(mocks.Injector)
err := nm.Initialize()
if err != nil {
t.Fatalf("expected no error during initialization, got %v", err)
}

// Call the ConfigureDNS method and expect an error due to missing DNS address
err = nm.ConfigureDNS()
if err == nil {
t.Fatalf("expected error, got nil")
}
expectedError := "DNS address is not configured"
if !strings.Contains(err.Error(), expectedError) {
t.Fatalf("expected error %q, got %q", expectedError, err.Error())
}
})

t.Run("SystemdResolvedNotInUse", func(t *testing.T) {
mocks := setupLinuxNetworkManagerMocks()

Expand Down
33 changes: 13 additions & 20 deletions pkg/network/network.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ type BaseNetworkManager struct {
configHandler config.ConfigHandler
networkInterfaceProvider NetworkInterfaceProvider
services []services.Service
isLocalhost bool
}

// NewNetworkManager creates a new NetworkManager
Expand Down Expand Up @@ -75,27 +74,16 @@ func (n *BaseNetworkManager) Initialize() error {

n.services = serviceList

vmDriver := n.configHandler.GetString("vm.driver")
n.isLocalhost = vmDriver == "docker-desktop"

if n.isLocalhost {
for _, service := range n.services {
if err := service.SetAddress("127.0.0.1"); err != nil {
return fmt.Errorf("error setting address for service: %w", err)
}
}
} else {
networkCIDR := n.configHandler.GetString("network.cidr_block")
if networkCIDR == "" {
networkCIDR = constants.DEFAULT_NETWORK_CIDR
if err := n.configHandler.SetContextValue("network.cidr_block", networkCIDR); err != nil {
return fmt.Errorf("error setting default network CIDR: %w", err)
}
}
if err := assignIPAddresses(n.services, &networkCIDR); err != nil {
return fmt.Errorf("error assigning IP addresses: %w", err)
networkCIDR := n.configHandler.GetString("network.cidr_block")
if networkCIDR == "" {
networkCIDR = constants.DEFAULT_NETWORK_CIDR
if err := n.configHandler.SetContextValue("network.cidr_block", networkCIDR); err != nil {
return fmt.Errorf("error setting default network CIDR: %w", err)
}
}
if err := assignIPAddresses(n.services, &networkCIDR); err != nil {
return fmt.Errorf("error assigning IP addresses: %w", err)
}

return nil
}
Expand All @@ -109,6 +97,11 @@ func (n *BaseNetworkManager) ConfigureGuest() error {
// Ensure BaseNetworkManager implements NetworkManager
var _ NetworkManager = (*BaseNetworkManager)(nil)

// isLocalhostMode checks if the system is in localhost mode
func (n *BaseNetworkManager) isLocalhostMode() bool {
return n.configHandler.GetString("vm.driver") == "docker-desktop"
}

// assignIPAddresses assigns IP addresses to services based on the network CIDR.
var assignIPAddresses = func(services []services.Service, networkCIDR *string) error {
if networkCIDR == nil || *networkCIDR == "" {
Expand Down
Loading
Loading