diff --git a/.vscode/launch.json b/.vscode/launch.json index 86883b57b..2ed6cace2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -22,7 +22,7 @@ "request": "launch", "mode": "auto", "program": "${workspaceFolder}/cmd/windsor/main.go", - "args": ["init", "local"] + "args": ["init", "local", "--vm-driver", "colima"] }, { "name": "Windsor Up", diff --git a/api/v1alpha1/cluster/cluster_config.go b/api/v1alpha1/cluster/cluster_config.go index 7692ab11f..c5f987905 100644 --- a/api/v1alpha1/cluster/cluster_config.go +++ b/api/v1alpha1/cluster/cluster_config.go @@ -9,14 +9,14 @@ type ClusterConfig struct { CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` } `yaml:"controlplanes,omitempty"` Workers struct { Count *int `yaml:"count,omitempty"` CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` } `yaml:"workers,omitempty"` } @@ -25,7 +25,7 @@ type NodeConfig struct { Hostname *string `yaml:"hostname"` Node *string `yaml:"node,omitempty"` Endpoint *string `yaml:"endpoint,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` } // Merge performs a deep merge of the current ClusterConfig with another ClusterConfig. @@ -66,9 +66,9 @@ func (base *ClusterConfig) Merge(overlay *ClusterConfig) { base.Workers.Nodes[key] = node } } - if overlay.Workers.NodePorts != nil { - base.Workers.NodePorts = make([]string, len(overlay.Workers.NodePorts)) - copy(base.Workers.NodePorts, overlay.Workers.NodePorts) + if overlay.Workers.HostPorts != nil { + base.Workers.HostPorts = make([]string, len(overlay.Workers.HostPorts)) + copy(base.Workers.HostPorts, overlay.Workers.HostPorts) } } @@ -84,11 +84,11 @@ func (c *ClusterConfig) Copy() *ClusterConfig { Hostname: node.Hostname, Node: node.Node, Endpoint: node.Endpoint, - NodePorts: append([]string{}, node.NodePorts...), // Copy NodePorts for each node + HostPorts: append([]string{}, node.HostPorts...), // Copy HostPorts for each node } } - controlPlanesNodePortsCopy := make([]string, len(c.ControlPlanes.NodePorts)) - copy(controlPlanesNodePortsCopy, c.ControlPlanes.NodePorts) + controlPlanesHostPortsCopy := make([]string, len(c.ControlPlanes.HostPorts)) + copy(controlPlanesHostPortsCopy, c.ControlPlanes.HostPorts) workersNodesCopy := make(map[string]NodeConfig, len(c.Workers.Nodes)) for key, node := range c.Workers.Nodes { @@ -96,11 +96,11 @@ func (c *ClusterConfig) Copy() *ClusterConfig { Hostname: node.Hostname, Node: node.Node, Endpoint: node.Endpoint, - NodePorts: append([]string{}, node.NodePorts...), // Copy NodePorts for each node + HostPorts: append([]string{}, node.HostPorts...), // Copy HostPorts for each node } } - workersNodePortsCopy := make([]string, len(c.Workers.NodePorts)) - copy(workersNodePortsCopy, c.Workers.NodePorts) + workersHostPortsCopy := make([]string, len(c.Workers.HostPorts)) + copy(workersHostPortsCopy, c.Workers.HostPorts) return &ClusterConfig{ Enabled: c.Enabled, @@ -110,26 +110,26 @@ func (c *ClusterConfig) Copy() *ClusterConfig { CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: c.ControlPlanes.Count, CPU: c.ControlPlanes.CPU, Memory: c.ControlPlanes.Memory, Nodes: controlPlanesNodesCopy, - NodePorts: controlPlanesNodePortsCopy, + HostPorts: controlPlanesHostPortsCopy, }, Workers: struct { Count *int `yaml:"count,omitempty"` CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: c.Workers.Count, CPU: c.Workers.CPU, Memory: c.Workers.Memory, Nodes: workersNodesCopy, - NodePorts: workersNodePortsCopy, + HostPorts: workersHostPortsCopy, }, } } diff --git a/api/v1alpha1/cluster/cluster_config_test.go b/api/v1alpha1/cluster/cluster_config_test.go index 98d6d0254..1abfd7e60 100644 --- a/api/v1alpha1/cluster/cluster_config_test.go +++ b/api/v1alpha1/cluster/cluster_config_test.go @@ -27,7 +27,7 @@ func TestClusterConfig_Merge(t *testing.T) { CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: ptrInt(3), CPU: ptrInt(4), @@ -41,7 +41,7 @@ func TestClusterConfig_Merge(t *testing.T) { CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: ptrInt(5), CPU: ptrInt(2), @@ -49,7 +49,7 @@ func TestClusterConfig_Merge(t *testing.T) { Nodes: map[string]NodeConfig{ "worker1": {Hostname: ptrString("base-worker1")}, }, - NodePorts: []string{"8080", "9090"}, + HostPorts: []string{"8080", "9090"}, }, } @@ -61,7 +61,7 @@ func TestClusterConfig_Merge(t *testing.T) { CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: ptrInt(1), CPU: ptrInt(2), @@ -75,7 +75,7 @@ func TestClusterConfig_Merge(t *testing.T) { CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: ptrInt(3), CPU: ptrInt(1), @@ -83,7 +83,7 @@ func TestClusterConfig_Merge(t *testing.T) { Nodes: map[string]NodeConfig{ "worker2": {Hostname: ptrString("overlay-worker2")}, }, - NodePorts: []string{"8082", "9092"}, + HostPorts: []string{"8082", "9092"}, }, } @@ -95,8 +95,8 @@ func TestClusterConfig_Merge(t *testing.T) { if base.Driver == nil || *base.Driver != "overlay-driver" { t.Errorf("Driver mismatch: expected 'overlay-driver', got '%s'", *base.Driver) } - if len(base.Workers.NodePorts) != 2 || base.Workers.NodePorts[0] != "8082" || base.Workers.NodePorts[1] != "9092" { - t.Errorf("NodePorts mismatch: expected ['8082', '9092'], got %v", base.Workers.NodePorts) + if len(base.Workers.HostPorts) != 2 || base.Workers.HostPorts[0] != "8082" || base.Workers.HostPorts[1] != "9092" { + t.Errorf("HostPorts mismatch: expected ['8082', '9092'], got %v", base.Workers.HostPorts) } if base.ControlPlanes.Count == nil || *base.ControlPlanes.Count != 1 { t.Errorf("ControlPlanes Count mismatch: expected 1, got %v", *base.ControlPlanes.Count) @@ -133,26 +133,26 @@ func TestClusterConfig_Merge(t *testing.T) { CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: nil, CPU: nil, Memory: nil, Nodes: nil, - NodePorts: nil, + HostPorts: nil, }, Workers: struct { Count *int `yaml:"count,omitempty"` CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: nil, CPU: nil, Memory: nil, Nodes: nil, - NodePorts: nil, + HostPorts: nil, }, } @@ -164,26 +164,26 @@ func TestClusterConfig_Merge(t *testing.T) { CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: nil, CPU: nil, Memory: nil, Nodes: nil, - NodePorts: nil, + HostPorts: nil, }, Workers: struct { Count *int `yaml:"count,omitempty"` CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: nil, CPU: nil, Memory: nil, Nodes: nil, - NodePorts: nil, + HostPorts: nil, }, } @@ -195,8 +195,8 @@ func TestClusterConfig_Merge(t *testing.T) { if base.Driver != nil { t.Errorf("Driver mismatch: expected nil, got '%s'", *base.Driver) } - if base.Workers.NodePorts != nil { - t.Errorf("NodePorts mismatch: expected nil, got %v", base.Workers.NodePorts) + if base.Workers.HostPorts != nil { + t.Errorf("HostPorts mismatch: expected nil, got %v", base.Workers.HostPorts) } if base.ControlPlanes.Count != nil { t.Errorf("ControlPlanes Count mismatch: expected nil, got %v", *base.ControlPlanes.Count) @@ -235,7 +235,7 @@ func TestClusterConfig_Copy(t *testing.T) { CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: ptrInt(3), CPU: ptrInt(4), @@ -243,14 +243,14 @@ func TestClusterConfig_Copy(t *testing.T) { Nodes: map[string]NodeConfig{ "node1": {Hostname: ptrString("original-node1")}, }, - NodePorts: []string{"1000:1000/tcp", "2000:2000/tcp"}, + HostPorts: []string{"1000:1000/tcp", "2000:2000/tcp"}, }, Workers: struct { Count *int `yaml:"count,omitempty"` CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: ptrInt(5), CPU: ptrInt(2), @@ -258,7 +258,7 @@ func TestClusterConfig_Copy(t *testing.T) { Nodes: map[string]NodeConfig{ "worker1": {Hostname: ptrString("original-worker1")}, }, - NodePorts: []string{"3000:3000/tcp", "4000:4000/tcp"}, + HostPorts: []string{"3000:3000/tcp", "4000:4000/tcp"}, }, } @@ -270,12 +270,12 @@ func TestClusterConfig_Copy(t *testing.T) { if original.Driver == nil || copy.Driver == nil || *original.Driver != *copy.Driver { t.Errorf("Driver mismatch: expected %v, got %v", *original.Driver, *copy.Driver) } - if len(original.Workers.NodePorts) != len(copy.Workers.NodePorts) { - t.Errorf("Workers NodePorts length mismatch: expected %d, got %d", len(original.Workers.NodePorts), len(copy.Workers.NodePorts)) + if len(original.Workers.HostPorts) != len(copy.Workers.HostPorts) { + t.Errorf("Workers HostPorts length mismatch: expected %d, got %d", len(original.Workers.HostPorts), len(copy.Workers.HostPorts)) } - for i, port := range original.Workers.NodePorts { - if port != copy.Workers.NodePorts[i] { - t.Errorf("Workers NodePorts mismatch at index %d: expected %v, got %v", i, port, copy.Workers.NodePorts[i]) + for i, port := range original.Workers.HostPorts { + if port != copy.Workers.HostPorts[i] { + t.Errorf("Workers HostPorts mismatch at index %d: expected %v, got %v", i, port, copy.Workers.HostPorts[i]) } } if original.Workers.Count == nil || copy.Workers.Count == nil || *original.Workers.Count != *copy.Workers.Count { @@ -296,8 +296,8 @@ func TestClusterConfig_Copy(t *testing.T) { } } - if len(original.Workers.NodePorts) != len(copy.Workers.NodePorts) || original.Workers.NodePorts[0] != copy.Workers.NodePorts[0] || original.Workers.NodePorts[1] != copy.Workers.NodePorts[1] { - t.Errorf("NodePorts mismatch: expected %v, got %v", original.Workers.NodePorts, copy.Workers.NodePorts) + if len(original.Workers.HostPorts) != len(copy.Workers.HostPorts) || original.Workers.HostPorts[0] != copy.Workers.HostPorts[0] || original.Workers.HostPorts[1] != copy.Workers.HostPorts[1] { + t.Errorf("HostPorts mismatch: expected %v, got %v", original.Workers.HostPorts, copy.Workers.HostPorts) } if original.ControlPlanes.Count == nil || copy.ControlPlanes.Count == nil || *original.ControlPlanes.Count != *copy.ControlPlanes.Count { t.Errorf("ControlPlanes Count mismatch: expected %v, got %v", *original.ControlPlanes.Count, *copy.ControlPlanes.Count) diff --git a/api/v1alpha1/dns/dns_config.go b/api/v1alpha1/dns/dns_config.go index 767cbbb94..f0c8aa258 100644 --- a/api/v1alpha1/dns/dns_config.go +++ b/api/v1alpha1/dns/dns_config.go @@ -2,9 +2,10 @@ package dns // DNSConfig represents the DNS configuration type DNSConfig struct { - Enabled *bool `yaml:"enabled"` + Enabled *bool `yaml:"enabled,omitempty"` Domain *string `yaml:"domain,omitempty"` Address *string `yaml:"address,omitempty"` + Forward []string `yaml:"forward,omitempty"` Records []string `yaml:"records,omitempty"` } @@ -19,6 +20,9 @@ func (base *DNSConfig) Merge(overlay *DNSConfig) { if overlay.Address != nil { base.Address = overlay.Address } + if overlay.Forward != nil { + base.Forward = overlay.Forward + } if overlay.Records != nil { base.Records = overlay.Records } @@ -33,6 +37,7 @@ func (c *DNSConfig) Copy() *DNSConfig { Enabled: c.Enabled, Domain: c.Domain, Address: c.Address, + Forward: c.Forward, Records: c.Records, } } diff --git a/api/v1alpha1/dns/dns_config_test.go b/api/v1alpha1/dns/dns_config_test.go index f60093ecb..0e81c1854 100644 --- a/api/v1alpha1/dns/dns_config_test.go +++ b/api/v1alpha1/dns/dns_config_test.go @@ -17,6 +17,7 @@ func TestDNSConfig_Merge(t *testing.T) { Enabled: ptrBool(true), Domain: ptrString("base-domain"), Address: ptrString("base-address"), + Forward: []string{"8.8.8.8", "8.8.4.4"}, Records: []string{"127.0.0.1 base-domain", "192.168.1.1 base-domain"}, } @@ -24,6 +25,7 @@ func TestDNSConfig_Merge(t *testing.T) { Enabled: ptrBool(false), Domain: ptrString("overlay-domain"), Address: ptrString("overlay-address"), + Forward: []string{"1.1.1.1", "1.0.0.1"}, Records: []string{"127.0.0.2 overlay-domain", "192.168.1.2 overlay-domain"}, } @@ -38,6 +40,9 @@ func TestDNSConfig_Merge(t *testing.T) { if base.Address == nil || *base.Address != "overlay-address" { t.Errorf("Address mismatch: expected %v, got %v", "overlay-address", *base.Address) } + if len(base.Forward) != 2 || base.Forward[0] != "1.1.1.1" || base.Forward[1] != "1.0.0.1" { + t.Errorf("Forward mismatch: expected %v, got %v", []string{"1.1.1.1", "1.0.0.1"}, base.Forward) + } if len(base.Records) != 2 || base.Records[0] != "127.0.0.2 overlay-domain" || base.Records[1] != "192.168.1.2 overlay-domain" { t.Errorf("Records mismatch: expected %v, got %v", []string{"127.0.0.2 overlay-domain", "192.168.1.2 overlay-domain"}, base.Records) } @@ -48,6 +53,7 @@ func TestDNSConfig_Merge(t *testing.T) { Enabled: ptrBool(true), Domain: ptrString("base-domain"), Address: ptrString("base-address"), + Forward: []string{"8.8.8.8", "8.8.4.4"}, Records: []string{"127.0.0.1 base-domain", "192.168.1.1 base-domain"}, } @@ -55,6 +61,7 @@ func TestDNSConfig_Merge(t *testing.T) { Enabled: nil, Domain: nil, Address: nil, + Forward: nil, Records: nil, } @@ -69,6 +76,9 @@ func TestDNSConfig_Merge(t *testing.T) { if base.Address == nil || *base.Address != "base-address" { t.Errorf("Address mismatch: expected %v, got %v", "base-address", *base.Address) } + if len(base.Forward) != 2 || base.Forward[0] != "8.8.8.8" || base.Forward[1] != "8.8.4.4" { + t.Errorf("Forward mismatch: expected %v, got %v", []string{"8.8.8.8", "8.8.4.4"}, base.Forward) + } if len(base.Records) != 2 || base.Records[0] != "127.0.0.1 base-domain" || base.Records[1] != "192.168.1.1 base-domain" { t.Errorf("Records mismatch: expected %v, got %v", []string{"127.0.0.1 base-domain", "192.168.1.1 base-domain"}, base.Records) } @@ -81,6 +91,7 @@ func TestDNSConfig_Copy(t *testing.T) { Enabled: ptrBool(true), Domain: ptrString("original-domain"), Address: ptrString("original-address"), + Forward: []string{"8.8.8.8", "8.8.4.4"}, Records: []string{"127.0.0.1 original-domain", "192.168.1.1 original-domain"}, } @@ -95,6 +106,9 @@ func TestDNSConfig_Copy(t *testing.T) { if original.Address == nil || copy.Address == nil || *original.Address != *copy.Address { t.Errorf("Address mismatch: expected %v, got %v", *original.Address, *copy.Address) } + if len(original.Forward) != len(copy.Forward) || original.Forward[0] != copy.Forward[0] || original.Forward[1] != copy.Forward[1] { + t.Errorf("Forward mismatch: expected %v, got %v", original.Forward, copy.Forward) + } if len(original.Records) != len(copy.Records) || original.Records[0] != copy.Records[0] || original.Records[1] != copy.Records[1] { t.Errorf("Records mismatch: expected %v, got %v", original.Records, copy.Records) } @@ -112,6 +126,10 @@ func TestDNSConfig_Copy(t *testing.T) { if original.Address == nil || *original.Address == *copy.Address { t.Errorf("Original Address was modified: expected %v, got %v", "original-address", *copy.Address) } + copy.Forward = []string{"1.1.1.1", "1.0.0.1"} + if len(original.Forward) != 2 || original.Forward[0] == copy.Forward[0] || original.Forward[1] == copy.Forward[1] { + t.Errorf("Original Forward was modified: expected %v, got %v", []string{"8.8.8.8", "8.8.4.4"}, copy.Forward) + } copy.Records = []string{"127.0.0.2 modified-domain", "192.168.1.2 modified-domain"} if len(original.Records) != 2 || original.Records[0] == copy.Records[0] || original.Records[1] == copy.Records[1] { t.Errorf("Original Records were modified: expected %v, got %v", []string{"127.0.0.1 original-domain", "192.168.1.1 original-domain"}, copy.Records) @@ -123,6 +141,7 @@ func TestDNSConfig_Copy(t *testing.T) { Enabled: nil, Domain: nil, Address: nil, + Forward: nil, Records: nil, } @@ -137,6 +156,9 @@ func TestDNSConfig_Copy(t *testing.T) { if copy.Address != nil { t.Errorf("Address mismatch: expected nil, got %v", copy.Address) } + if copy.Forward != nil { + t.Errorf("Forward mismatch: expected nil, got %v", copy.Forward) + } if copy.Records != nil { t.Errorf("Records mismatch: expected nil, got %v", copy.Records) } diff --git a/api/v1alpha1/docker/docker_config.go b/api/v1alpha1/docker/docker_config.go index 4be5e4db6..3dc9b3456 100644 --- a/api/v1alpha1/docker/docker_config.go +++ b/api/v1alpha1/docker/docker_config.go @@ -2,7 +2,7 @@ package docker // DockerConfig represents the Docker configuration type DockerConfig struct { - Enabled *bool `yaml:"enabled"` + Enabled *bool `yaml:"enabled,omitempty"` RegistryURL string `yaml:"registry_url,omitempty"` Registries map[string]RegistryConfig `yaml:"registries,omitempty"` } diff --git a/api/v1alpha1/terraform/terraform_config.go b/api/v1alpha1/terraform/terraform_config.go index 0609f1f56..930b2e74c 100644 --- a/api/v1alpha1/terraform/terraform_config.go +++ b/api/v1alpha1/terraform/terraform_config.go @@ -2,7 +2,7 @@ package terraform // TerraformConfig represents the Terraform configuration type TerraformConfig struct { - Enabled *bool `yaml:"enabled"` + Enabled *bool `yaml:"enabled,omitempty"` Backend *string `yaml:"backend,omitempty"` } diff --git a/cmd/init.go b/cmd/init.go index cc8297f61..b29327797 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -4,8 +4,11 @@ import ( "fmt" "os" "path/filepath" + "strings" "github.com/spf13/cobra" + "github.com/windsorcli/cli/api/v1alpha1" + "github.com/windsorcli/cli/pkg/config" ctrl "github.com/windsorcli/cli/pkg/controller" ) @@ -39,25 +42,44 @@ var initCmd = &cobra.Command{ return fmt.Errorf("Error adding current directory to trusted file: %w", err) } - // Resolve the config handler + // Resolve the config handler and determine the context name configHandler := controller.ResolveConfigHandler() - - var contextName string + contextName := "local" if len(args) == 1 { contextName = args[0] - } else { - contextName = configHandler.GetContext() + } else if currentContext := configHandler.GetContext(); currentContext != "" { + contextName = currentContext } // Set the context value - if contextName == "" { - contextName = "local" - } if err := configHandler.SetContext(contextName); err != nil { return fmt.Errorf("Error setting context value: %w", err) } - // Create the flag to config path mapping + // Determine the default configuration based on the vm-driver flag + vmDriverConfig := vmDriver + if vmDriverConfig == "" { + vmDriverConfig = configHandler.GetString("vm.driver") + if vmDriverConfig == "" && (contextName == "local" || strings.HasPrefix(contextName, "local-")) { + vmDriverConfig = "docker-desktop" + } + } + + // Set the default configuration if applicable + var defaultConfig *v1alpha1.Context + switch vmDriverConfig { + case "docker-desktop": + defaultConfig = &config.DefaultConfig_Containerized + case "colima": + defaultConfig = &config.DefaultConfig_FullVM + } + if defaultConfig != nil { + if err := configHandler.SetDefault(*defaultConfig); err != nil { + return fmt.Errorf("Error setting default config: %w", err) + } + } + + // Create the flag to config path mapping and set the configurations configurations := []struct { flagName string configPath string @@ -76,7 +98,6 @@ var initCmd = &cobra.Command{ {"git-livereload", "git.livereload.enabled", gitLivereload}, } - // Set the configurations for _, config := range configurations { if cmd.Flags().Changed(config.flagName) { err := configHandler.SetContextValue(config.configPath, config.value) @@ -86,7 +107,7 @@ var initCmd = &cobra.Command{ } } - // Get the cli configuration path using shell to get the project root + // Determine the cli configuration path projectRoot, err := shell.GetProjectRoot() if err != nil { return fmt.Errorf("Error retrieving project root: %w", err) @@ -94,16 +115,12 @@ var initCmd = &cobra.Command{ yamlPath := filepath.Join(projectRoot, "windsor.yaml") ymlPath := filepath.Join(projectRoot, "windsor.yml") - // Declare cliConfigPath variable var cliConfigPath string - - // Check if windsor.yaml exists if _, err := osStat(yamlPath); err == nil { cliConfigPath = yamlPath } else if _, err := osStat(ymlPath); err == nil { cliConfigPath = ymlPath } else { - // Default to windsor.yaml if neither file exists cliConfigPath = yamlPath } @@ -112,27 +129,19 @@ var initCmd = &cobra.Command{ return fmt.Errorf("Error saving config file: %w", err) } - // Create project components + // Create and initialize components if err := controller.CreateProjectComponents(); err != nil { return fmt.Errorf("Error creating project components: %w", err) } - - // Create service components if err := controller.CreateServiceComponents(); err != nil { return fmt.Errorf("Error creating service components: %w", err) } - - // Create virtualization components if err := controller.CreateVirtualizationComponents(); err != nil { return fmt.Errorf("Error creating virtualization components: %w", err) } - - // Create stack components if err := controller.CreateStackComponents(); err != nil { return fmt.Errorf("Error creating stack components: %w", err) } - - // Initialize components if err := controller.InitializeComponents(); err != nil { return fmt.Errorf("Error initializing components: %w", err) } diff --git a/cmd/init_test.go b/cmd/init_test.go index 7ffa0067c..0d0a19ce1 100644 --- a/cmd/init_test.go +++ b/cmd/init_test.go @@ -6,6 +6,7 @@ import ( "strings" "testing" + "github.com/windsorcli/cli/api/v1alpha1" "github.com/windsorcli/cli/pkg/config" ctrl "github.com/windsorcli/cli/pkg/controller" "github.com/windsorcli/cli/pkg/di" @@ -66,6 +67,7 @@ func TestInitCmd(t *testing.T) { t.Cleanup(func() { rootCmd.Args = originalArgs exitFunc = originalExitFunc + resetRootCmd() }) // Mock the exit function to prevent the test from exiting @@ -74,6 +76,7 @@ func TestInitCmd(t *testing.T) { } t.Run("Success", func(t *testing.T) { + // Setup mocks mocks := setupSafeInitCmdMocks() @@ -93,6 +96,7 @@ func TestInitCmd(t *testing.T) { }) t.Run("AllFlagsSet", func(t *testing.T) { + // Given a valid config handler mocks := setupSafeInitCmdMocks() @@ -123,8 +127,150 @@ func TestInitCmd(t *testing.T) { } }) + t.Run("VMDriverDockerDesktop", func(t *testing.T) { + + // Given a valid config handler + mocks := setupSafeInitCmdMocks() + + // Mock the GetString method to return "docker-desktop" for vm.driver + mocks.ConfigHandler.GetStringFunc = func(key string, defaultValue ...string) string { + if key == "vm.driver" { + return "docker-desktop" + } + return "" + } + + // Track if SetDefault is called with the correct config + setDefaultCalled := false + mocks.ConfigHandler.SetDefaultFunc = func(contextConfig v1alpha1.Context) error { + if contextConfig.VM != nil && contextConfig.VM.Driver != nil && *contextConfig.VM.Driver == "docker-desktop" { + setDefaultCalled = true + } + return nil + } + + // When the init command is executed with vm.driver set to "docker-desktop" + output := captureStderr(func() { + rootCmd.SetArgs([]string{"init", "test-context", "--vm-driver", "docker-desktop"}) + err := Execute(mocks.Controller) + if err != nil { + t.Fatalf("Execute() error = %v", err) + } + }) + + // Then the output should indicate success + expectedOutput := "Initialization successful\n" + if output != expectedOutput { + t.Errorf("Expected output %q, got %q", expectedOutput, output) + } + + // Check if SetDefault was called correctly + if !setDefaultCalled { + t.Errorf("Expected SetDefault to be called with vm.driver 'docker-desktop'") + } + }) + + t.Run("ErrorSettingDefaultContainerizedConfig", func(t *testing.T) { + + // Given a mock config handler that returns an error when setting default containerized config + mocks := setupSafeInitCmdMocks() + mocks.ConfigHandler.SetDefaultFunc = func(contextConfig v1alpha1.Context) error { + if contextConfig.VM != nil && *contextConfig.VM.Driver == "docker-desktop" { + return fmt.Errorf("error setting default containerized config") + } + return nil + } + + // Mock the GetString method to return "docker-desktop" for vm.driver + mocks.ConfigHandler.GetStringFunc = func(key string, defaultValue ...string) string { + if key == "vm.driver" { + return "docker-desktop" + } + return "" + } + + // When the init command is executed with vm.driver set to "docker-desktop" + rootCmd.SetArgs([]string{"init", "test-context", "--vm-driver", "docker-desktop"}) + err := Execute(mocks.Controller) + + // Then an error should be returned + if err == nil || !strings.Contains(err.Error(), "error setting default containerized config") { + t.Fatalf("Expected error setting default containerized config, got %v", err) + } + }) + + t.Run("VMDriverColima", func(t *testing.T) { + // Given a valid config handler + mocks := setupSafeInitCmdMocks() + + // Mock the GetString method to return "colima" for vm.driver + mocks.ConfigHandler.GetStringFunc = func(key string, defaultValue ...string) string { + if key == "vm.driver" { + return "colima" + } + return "" + } + + // Track if SetDefault is called with the correct config + setDefaultCalled := false + mocks.ConfigHandler.SetDefaultFunc = func(contextConfig v1alpha1.Context) error { + if contextConfig.VM != nil && *contextConfig.VM.Driver == "colima" { + setDefaultCalled = true + } + return nil + } + + // When the init command is executed with vm.driver set to "colima" + rootCmd.SetArgs([]string{"init", "test-context", "--vm-driver", "colima"}) + output := captureStderr(func() { + err := Execute(mocks.Controller) + if err != nil { + t.Fatalf("Execute() error = %v", err) + } + }) + + // Then the output should indicate success + expectedOutput := "Initialization successful\n" + if output != expectedOutput { + t.Errorf("Expected output %q, got %q", expectedOutput, output) + } + + // Validate that SetDefault was called with the correct configuration + if !setDefaultCalled { + t.Error("Expected SetDefault to be called with DefaultConfig_FullVM, but it was not") + } + }) + + t.Run("ErrorSettingDefaultFullVMConfig", func(t *testing.T) { + + // Given a mock config handler that returns an error when setting default full VM config + mocks := setupSafeInitCmdMocks() + mocks.ConfigHandler.SetDefaultFunc = func(contextConfig v1alpha1.Context) error { + if contextConfig.VM != nil && *contextConfig.VM.Driver == "colima" { + return fmt.Errorf("error setting default full VM config") + } + return nil + } + + // Mock the GetString method to return "colima" for vm.driver + mocks.ConfigHandler.GetStringFunc = func(key string, defaultValue ...string) string { + if key == "vm.driver" { + return "colima" + } + return "" + } + + // When the init command is executed with vm.driver set to "colima" + rootCmd.SetArgs([]string{"init", "test-context", "--vm-driver", "colima"}) + err := Execute(mocks.Controller) + + // Then an error should be returned + if err == nil || !strings.Contains(err.Error(), "error setting default full VM config") { + t.Fatalf("Expected error setting default full VM config, got %v", err) + } + }) + t.Run("ErrorAddingCurrentDirToTrustedFile", func(t *testing.T) { - defer resetRootCmd() // Given a mock shell that returns an error when adding current directory to trusted file injector := di.NewInjector() @@ -240,9 +386,16 @@ func TestInitCmd(t *testing.T) { // Given a valid config handler mocks := setupSafeInitCmdMocks() - // Mock GetProjectRoot to return an error + // Counter to track the number of times GetProjectRootFunc is called + callCount := 0 + + // Mock GetProjectRoot to return an error only on the second call mocks.Shell.GetProjectRootFunc = func() (string, error) { - return "", fmt.Errorf("mocked error retrieving project root") + callCount++ + if callCount == 2 { + return "", fmt.Errorf("mocked error retrieving project root") + } + return "/mock/project/root", nil } // When the init command is executed diff --git a/cmd/root.go b/cmd/root.go index 595b14220..411d860c1 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -7,7 +7,6 @@ import ( "path/filepath" "github.com/spf13/cobra" - "github.com/windsorcli/cli/pkg/config" ctrl "github.com/windsorcli/cli/pkg/controller" ) @@ -56,27 +55,12 @@ func preRunEInitializeCommonComponents(cmd *cobra.Command, args []string) error return fmt.Errorf("No config handler found") } - contextName := configHandler.GetContext() - // Set the verbosity shell := controller.ResolveShell() if shell != nil { shell.SetVerbosity(verbose) } - // If the context is local or starts with "local-", set the defaults to the default local config - if contextName == "local" || len(contextName) > 6 && contextName[:6] == "local-" { - err := configHandler.SetDefault(config.DefaultLocalConfig) - if err != nil { - return fmt.Errorf("error setting default local config: %w", err) - } - } else { - err := configHandler.SetDefault(config.DefaultConfig) - if err != nil { - return fmt.Errorf("error setting default config: %w", err) - } - } - // Determine the cliConfig path var cliConfigPath string if cliConfigPath = os.Getenv("WINDSORCONFIG"); cliConfigPath == "" { @@ -99,6 +83,9 @@ func preRunEInitializeCommonComponents(cmd *cobra.Command, args []string) error } } + // Load the current context + configHandler.GetContext() + // Load the configuration if a config path was determined if cliConfigPath != "" { if err := configHandler.LoadConfig(cliConfigPath); err != nil { diff --git a/cmd/root_test.go b/cmd/root_test.go index 1114ccb58..12bb5773e 100644 --- a/cmd/root_test.go +++ b/cmd/root_test.go @@ -6,12 +6,10 @@ import ( "fmt" "io" "os" - "reflect" "strings" "testing" "github.com/spf13/cobra" - "github.com/windsorcli/cli/api/v1alpha1" "github.com/windsorcli/cli/pkg/config" ctrl "github.com/windsorcli/cli/pkg/controller" "github.com/windsorcli/cli/pkg/di" @@ -221,101 +219,39 @@ func TestRoot_preRunEInitializeCommonComponents(t *testing.T) { } }) - // t.Run("ErrorLoadingConfig", func(t *testing.T) { - // mocks := setupSafeRootMocks() + // t.Run("ErrorSettingDefaultConfig", func(t *testing.T) { + // // Mock the injector + // injector := di.NewInjector() - // // Mock LoadConfig to return an error - // mocks.Controller.ResolveConfigHandlerFunc = func() config.ConfigHandler { - // mockConfigHandler := config.NewMockConfigHandler() - // mockConfigHandler.LoadConfigFunc = func(path string) error { - // return fmt.Errorf("mocked error loading config") + // // Mock the controller + // mockController := ctrl.NewMockController(injector) + + // // Mock ResolveConfigHandler to return a mock config handler + // mockConfigHandler := config.NewMockConfigHandler() + // mockConfigHandler.SetDefaultFunc = func(cfg v1alpha1.Context) error { + // if reflect.DeepEqual(cfg, config.DefaultConfig) { + // return fmt.Errorf("mocked error setting default config") // } + // return nil + // } + // mockController.ResolveConfigHandlerFunc = func() config.ConfigHandler { // return mockConfigHandler // } + // mockConfigHandler.GetContextFunc = func() string { + // return "production" + // } // // Create a new command and register the controller // cmd := &cobra.Command{} - // cmd.SetContext(context.WithValue(context.Background(), controllerKey, mocks.Controller)) + // cmd.SetContext(context.WithValue(context.Background(), controllerKey, mockController)) // // When preRunEInitializeCommonComponents is called // err := preRunEInitializeCommonComponents(cmd, nil) // // Then an error should be returned - // expectedError := "mocked error loading config" + // expectedError := "mocked error setting default config" // if err == nil || !strings.Contains(err.Error(), expectedError) { // t.Fatalf("Expected error to contain %q, got %v", expectedError, err) // } // }) - - t.Run("ErrorSettingDefaultLocalConfig", func(t *testing.T) { - // Mock the injector - injector := di.NewInjector() - - // Mock the controller - mockController := ctrl.NewMockController(injector) - - // Mock ResolveConfigHandler to return a mock config handler - mockConfigHandler := config.NewMockConfigHandler() - mockConfigHandler.SetDefaultFunc = func(cfg v1alpha1.Context) error { - if reflect.DeepEqual(cfg, config.DefaultLocalConfig) { - return fmt.Errorf("mocked error setting default local config") - } - return nil - } - mockController.ResolveConfigHandlerFunc = func() config.ConfigHandler { - return mockConfigHandler - } - mockConfigHandler.GetContextFunc = func() string { - return "local" - } - - // Create a new command and register the controller - cmd := &cobra.Command{} - cmd.SetContext(context.WithValue(context.Background(), controllerKey, mockController)) - - // When preRunEInitializeCommonComponents is called - err := preRunEInitializeCommonComponents(cmd, nil) - - // Then an error should be returned - expectedError := "mocked error setting default local config" - if err == nil || !strings.Contains(err.Error(), expectedError) { - t.Fatalf("Expected error to contain %q, got %v", expectedError, err) - } - }) - - t.Run("ErrorSettingDefaultConfig", func(t *testing.T) { - // Mock the injector - injector := di.NewInjector() - - // Mock the controller - mockController := ctrl.NewMockController(injector) - - // Mock ResolveConfigHandler to return a mock config handler - mockConfigHandler := config.NewMockConfigHandler() - mockConfigHandler.SetDefaultFunc = func(cfg v1alpha1.Context) error { - if reflect.DeepEqual(cfg, config.DefaultConfig) { - return fmt.Errorf("mocked error setting default config") - } - return nil - } - mockController.ResolveConfigHandlerFunc = func() config.ConfigHandler { - return mockConfigHandler - } - mockConfigHandler.GetContextFunc = func() string { - return "production" - } - - // Create a new command and register the controller - cmd := &cobra.Command{} - cmd.SetContext(context.WithValue(context.Background(), controllerKey, mockController)) - - // When preRunEInitializeCommonComponents is called - err := preRunEInitializeCommonComponents(cmd, nil) - - // Then an error should be returned - expectedError := "mocked error setting default config" - if err == nil || !strings.Contains(err.Error(), expectedError) { - t.Fatalf("Expected error to contain %q, got %v", expectedError, err) - } - }) } diff --git a/pkg/blueprint/blueprint_handler.go b/pkg/blueprint/blueprint_handler.go index f263d944c..050f30f18 100644 --- a/pkg/blueprint/blueprint_handler.go +++ b/pkg/blueprint/blueprint_handler.go @@ -905,6 +905,8 @@ func (b *BaseBlueprintHandler) applyConfigMap() error { "DOMAIN": domain, "CONTEXT": context, "LOADBALANCER_IP_RANGE": loadBalancerIPRange, + "LOADBALANCER_IP_START": lbStart, + "LOADBALANCER_IP_END": lbEnd, "REGISTRY_URL": registryURL, }, } diff --git a/pkg/blueprint/templates/local.jsonnet b/pkg/blueprint/templates/local.jsonnet index 3a954acc3..9d3222eb2 100644 --- a/pkg/blueprint/templates/local.jsonnet +++ b/pkg/blueprint/templates/local.jsonnet @@ -263,27 +263,113 @@ local registryMirrors = std.foldl( } } ] else [], - kustomize: [ - { - name: "ingress-base", - path: "ingress/base", - source: "core", - components: [ - "nginx", - "nginx/nodeport-web", - "nginx/nodeport-flux-webhook" - ], - }, - { - name: "gitops", - path: "gitops/flux", - source: "core", - dependsOn: [ - "ingress-base", - ], - components: [ - "webhook", - ], - }, - ] +kustomize: [ + { + name: "policy-base", + path: "policy/base", + components: [ + "kyverno" + ], + }, + { + name: "policy-resources", + path: "policy/resources", + dependsOn: [ + "policy-base" + ], + }, + { + name: "pki-base", + path: "pki/base", + dependsOn: [ + "policy-resources" + ], + force: true, + components: [ + "cert-manager", + "trust-manager" + ], + }, + { + name: "pki-resources", + path: "pki/resources", + dependsOn: [ + "pki-base" + ], + force: true, + components: [ + "private-issuer/ca", + "public-issuer/selfsigned" + ], + }, + { + name: "ingress-base", + path: "ingress/base", + dependsOn: [ + "pki-resources" + ], + force: true, + components: if context.vm.driver == "colima" then [ + "nginx", + "nginx/loadbalancer", + "nginx/coredns", + "nginx/flux-webhook", + "nginx/web" + ] else [ + "nginx", + "nginx/nodeport", + "nginx/flux-webhook", + "nginx/web" + ], + }, + { + name: "gitops", + path: "gitops/flux", + dependsOn: [ + "ingress-base" + ], + force: true, + components: [ + "webhook" + ], + }, +] + (if context.vm.driver == "colima" then [ + { + name: "dns", + path: "dns", + dependsOn: [ + "pki-base" + ], + force: true, + components: [ + "coredns", + "coredns/etcd", + "external-dns", + "external-dns/coredns", + "external-dns/ingress" + ], + }, + { + name: "lb-base", + path: "lb/base", + dependsOn: [ + "policy-resources" + ], + force: true, + components: [ + "metallb" + ], + }, + { + name: "lb-resources", + path: "lb/resources", + dependsOn: [ + "lb-base" + ], + force: true, + components: [ + "metallb/layer2" + ], + } +] else []), } diff --git a/pkg/config/config_handler.go b/pkg/config/config_handler.go index e3880a1d0..fc7f09eaa 100644 --- a/pkg/config/config_handler.go +++ b/pkg/config/config_handler.go @@ -71,6 +71,7 @@ type BaseConfigHandler struct { ConfigHandler injector di.Injector shell shell.Shell + config v1alpha1.Config context string } diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index 57f1fdf87..886a6794c 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -1,8 +1,15 @@ +// This file defines default configurations for various components of the Windsor CLI application. +// It includes configurations for AWS, Docker, Terraform, Cluster, DNS, and VM settings. +// The configurations are structured using the v1alpha1.Context type, which aggregates settings +// from different modules like AWS, Docker, and others. The file also defines common configurations +// that can be reused across different contexts, such as commonDockerConfig, commonGitConfig, etc. +// These common configurations are used to create specific default configurations like +// DefaultConfig_Containerized and DefaultConfig_FullVM. + package config import ( "github.com/windsorcli/cli/api/v1alpha1" - "github.com/windsorcli/cli/api/v1alpha1/aws" "github.com/windsorcli/cli/api/v1alpha1/cluster" "github.com/windsorcli/cli/api/v1alpha1/dns" "github.com/windsorcli/cli/api/v1alpha1/docker" @@ -14,77 +21,88 @@ import ( ) // DefaultConfig returns the default configuration -var DefaultConfig = v1alpha1.Context{ - Environment: map[string]string{}, - AWS: &aws.AWSConfig{ - Enabled: nil, - AWSEndpointURL: nil, - AWSProfile: nil, - S3Hostname: nil, - MWAAEndpoint: nil, - Localstack: &aws.LocalstackConfig{ - Enabled: nil, - Services: nil, +var DefaultConfig = v1alpha1.Context{} + +var commonDockerConfig = docker.DockerConfig{ + Enabled: ptrBool(true), + Registries: map[string]docker.RegistryConfig{ + "registry.test": {}, + "registry-1.docker.io": { + Remote: "https://registry-1.docker.io", + Local: "https://docker.io", + }, + "registry.k8s.io": { + Remote: "https://registry.k8s.io", + }, + "gcr.io": { + Remote: "https://gcr.io", + }, + "ghcr.io": { + Remote: "https://ghcr.io", + }, + "quay.io": { + Remote: "https://quay.io", }, }, - Docker: &docker.DockerConfig{ - Enabled: nil, - Registries: map[string]docker.RegistryConfig{}, +} + +var commonGitConfig = git.GitConfig{ + Livereload: &git.GitLivereloadConfig{ + Enabled: ptrBool(true), + RsyncExclude: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_RSYNC_EXCLUDE), + RsyncProtect: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_RSYNC_PROTECT), + Username: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_USERNAME), + Password: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_PASSWORD), + WebhookUrl: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_WEBHOOK_URL), + Image: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_IMAGE), + VerifySsl: ptrBool(false), }, - Terraform: &terraform.TerraformConfig{ - Enabled: nil, - Backend: nil, +} + +var commonTerraformConfig = terraform.TerraformConfig{ + Enabled: ptrBool(true), + Backend: ptrString("local"), +} + +var commonClusterConfig = cluster.ClusterConfig{ + Enabled: ptrBool(true), + Driver: ptrString("talos"), + ControlPlanes: struct { + Count *int `yaml:"count,omitempty"` + CPU *int `yaml:"cpu,omitempty"` + Memory *int `yaml:"memory,omitempty"` + Nodes map[string]cluster.NodeConfig `yaml:"nodes,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` + }{ + Count: ptrInt(1), + CPU: ptrInt(constants.DEFAULT_TALOS_CONTROL_PLANE_CPU), + Memory: ptrInt(constants.DEFAULT_TALOS_CONTROL_PLANE_RAM), + Nodes: make(map[string]cluster.NodeConfig), }, - Cluster: nil, - Network: nil, - DNS: &dns.DNSConfig{ - Enabled: nil, - Domain: nil, - Address: nil, + Workers: struct { + Count *int `yaml:"count,omitempty"` + CPU *int `yaml:"cpu,omitempty"` + Memory *int `yaml:"memory,omitempty"` + Nodes map[string]cluster.NodeConfig `yaml:"nodes,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` + }{ + Count: ptrInt(1), + CPU: ptrInt(constants.DEFAULT_TALOS_WORKER_CPU), + Memory: ptrInt(constants.DEFAULT_TALOS_WORKER_RAM), + Nodes: make(map[string]cluster.NodeConfig), }, } -// DefaultLocalConfig returns the default configuration for the "local" context -var DefaultLocalConfig = v1alpha1.Context{ +var commonDNSConfig = dns.DNSConfig{ + Enabled: ptrBool(true), + Domain: ptrString("test"), +} + +var DefaultConfig_Containerized = v1alpha1.Context{ Environment: map[string]string{}, - Docker: &docker.DockerConfig{ - Enabled: ptrBool(true), - Registries: map[string]docker.RegistryConfig{ - "registry.test": {}, - "registry-1.docker.io": { - Remote: "https://registry-1.docker.io", - Local: "https://docker.io", - }, - "registry.k8s.io": { - Remote: "https://registry.k8s.io", - }, - "gcr.io": { - Remote: "https://gcr.io", - }, - "ghcr.io": { - Remote: "https://ghcr.io", - }, - "quay.io": { - Remote: "https://quay.io", - }, - }, - }, - Git: &git.GitConfig{ - Livereload: &git.GitLivereloadConfig{ - Enabled: ptrBool(true), - RsyncExclude: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_RSYNC_EXCLUDE), - RsyncProtect: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_RSYNC_PROTECT), - Username: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_USERNAME), - Password: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_PASSWORD), - WebhookUrl: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_WEBHOOK_URL), - Image: ptrString(constants.DEFAULT_GIT_LIVE_RELOAD_IMAGE), - VerifySsl: ptrBool(false), - }, - }, - Terraform: &terraform.TerraformConfig{ - Enabled: ptrBool(true), - Backend: ptrString("local"), - }, + Docker: commonDockerConfig.Copy(), + Git: commonGitConfig.Copy(), + Terraform: commonTerraformConfig.Copy(), Cluster: &cluster.ClusterConfig{ Enabled: ptrBool(true), Driver: ptrString("talos"), @@ -93,11 +111,11 @@ var DefaultLocalConfig = v1alpha1.Context{ CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]cluster.NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: ptrInt(1), - CPU: ptrInt(2), - Memory: ptrInt(2), + CPU: ptrInt(constants.DEFAULT_TALOS_CONTROL_PLANE_CPU), + Memory: ptrInt(constants.DEFAULT_TALOS_CONTROL_PLANE_RAM), Nodes: make(map[string]cluster.NodeConfig), }, Workers: struct { @@ -105,17 +123,32 @@ var DefaultLocalConfig = v1alpha1.Context{ CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]cluster.NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: ptrInt(1), - CPU: ptrInt(4), - Memory: ptrInt(4), + CPU: ptrInt(constants.DEFAULT_TALOS_WORKER_CPU), + Memory: ptrInt(constants.DEFAULT_TALOS_WORKER_RAM), Nodes: make(map[string]cluster.NodeConfig), - NodePorts: []string{"8080:30080/tcp", "8443:30443/tcp", "9292:30292/tcp"}, + HostPorts: []string{"8080:30080/tcp", "8443:30443/tcp", "9292:30292/tcp"}, }, }, + DNS: commonDNSConfig.Copy(), + VM: &vm.VMConfig{ + Driver: ptrString("docker-desktop"), + }, +} + +var DefaultConfig_FullVM = v1alpha1.Context{ + Environment: map[string]string{}, + Docker: commonDockerConfig.Copy(), + Git: commonGitConfig.Copy(), + Terraform: commonTerraformConfig.Copy(), + Cluster: commonClusterConfig.Copy(), + VM: &vm.VMConfig{ + Driver: ptrString("colima"), + }, Network: &network.NetworkConfig{ - CIDRBlock: ptrString("10.5.0.0/16"), + CIDRBlock: ptrString(constants.DEFAULT_NETWORK_CIDR), LoadBalancerIPs: &struct { Start *string `yaml:"start,omitempty"` End *string `yaml:"end,omitempty"` @@ -127,9 +160,10 @@ var DefaultLocalConfig = v1alpha1.Context{ DNS: &dns.DNSConfig{ Enabled: ptrBool(true), Domain: ptrString("test"), - Address: nil, - }, - VM: &vm.VMConfig{ - Driver: ptrString("docker-desktop"), + Forward: []string{ + "10.5.1.1", + "1.1.1.1", + "8.8.8.8", + }, }, } diff --git a/pkg/config/mock_config_handler_test.go b/pkg/config/mock_config_handler_test.go index e73e42d3a..10dbf1473 100644 --- a/pkg/config/mock_config_handler_test.go +++ b/pkg/config/mock_config_handler_test.go @@ -419,14 +419,14 @@ func TestMockConfigHandler_SetDefault(t *testing.T) { // And SetDefaultFunc updates the flag and checks the parameters mockHandler.SetDefaultFunc = func(context v1alpha1.Context) error { called = true - if !reflect.DeepEqual(context, DefaultLocalConfig) { - t.Errorf("Expected value %v, got %v", DefaultLocalConfig, context) + if !reflect.DeepEqual(context, DefaultConfig_Containerized) { + t.Errorf("Expected value %v, got %v", DefaultConfig_Containerized, context) } return nil } // When SetDefault is called - mockHandler.SetDefault(DefaultLocalConfig) + mockHandler.SetDefault(DefaultConfig_Containerized) // Then the function should be called if !called { @@ -439,7 +439,7 @@ func TestMockConfigHandler_SetDefault(t *testing.T) { mockHandler := NewMockConfigHandler() // When SetDefault is called - mockHandler.SetDefault(DefaultLocalConfig) + mockHandler.SetDefault(DefaultConfig_Containerized) // Then no error should occur }) diff --git a/pkg/config/yaml_config_handler.go b/pkg/config/yaml_config_handler.go index 9dfdb23e1..01d5c3ece 100644 --- a/pkg/config/yaml_config_handler.go +++ b/pkg/config/yaml_config_handler.go @@ -83,7 +83,7 @@ func (y *YamlConfigHandler) SaveConfig(path string) error { return nil } -// SetDefault sets the given context configuration as the default. Defaults to "local" if no current context is set. +// SetDefault sets the given context configuration as the default. func (y *YamlConfigHandler) SetDefault(context v1alpha1.Context) error { y.defaultContextConfig = context currentContext := y.GetContext() @@ -183,9 +183,7 @@ func (y *YamlConfigHandler) Set(path string, value interface{}) error { // SetContextValue sets a configuration value within the current context. func (y *YamlConfigHandler) SetContextValue(path string, value interface{}) error { - if y.context == "" { - return fmt.Errorf("current context is not set") - } + y.GetContext() currentContext := y.context fullPath := fmt.Sprintf("contexts.%s.%s", currentContext, path) diff --git a/pkg/config/yaml_config_handler_test.go b/pkg/config/yaml_config_handler_test.go index 5d30a78c7..52b33a67c 100644 --- a/pkg/config/yaml_config_handler_test.go +++ b/pkg/config/yaml_config_handler_test.go @@ -552,7 +552,7 @@ func TestYamlConfigHandler_GetInt(t *testing.T) { CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]cluster.NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Count: ptrInt(3), }, @@ -667,16 +667,16 @@ func TestYamlConfigHandler_GetStringSlice(t *testing.T) { CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]cluster.NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ - NodePorts: []string{"50000:50002/tcp", "30080:8080/tcp", "30443:8443/tcp"}, + HostPorts: []string{"50000:50002/tcp", "30080:8080/tcp", "30443:8443/tcp"}, }, }, }, } // When retrieving the slice value using GetStringSlice - value := handler.GetStringSlice("cluster.workers.nodeports") + value := handler.GetStringSlice("cluster.workers.hostports") // Then the returned slice should match the expected slice expectedSlice := []string{"50000:50002/tcp", "30080:8080/tcp", "30443:8443/tcp"} @@ -783,21 +783,21 @@ func TestYamlConfigHandler_SetContextValue(t *testing.T) { } }) - t.Run("ContextNotSet", func(t *testing.T) { - // Given a handler without a context set - mocks := setupSafeMocks() - handler := NewYamlConfigHandler(mocks.Injector) - handler.Initialize() + // t.Run("ContextNotSet", func(t *testing.T) { + // // Given a handler without a context set + // mocks := setupSafeMocks() + // handler := NewYamlConfigHandler(mocks.Injector) + // handler.Initialize() - // When calling SetContextValue - err := handler.SetContextValue("some.path", "someValue") + // // When calling SetContextValue + // err := handler.SetContextValue("some.path", "someValue") - // Then an error should be returned - expectedError := "current context is not set" - if err == nil || err.Error() != expectedError { - t.Errorf("Expected error '%s', got %v", expectedError, err) - } - }) + // // Then an error should be returned + // expectedError := "current context is not set" + // if err == nil || err.Error() != expectedError { + // t.Errorf("Expected error '%s', got %v", expectedError, err) + // } + // }) t.Run("InvalidPath", func(t *testing.T) { // Given a handler with a valid context set diff --git a/pkg/services/dns_service.go b/pkg/services/dns_service.go index ab4ffbd22..6144a2e78 100644 --- a/pkg/services/dns_service.go +++ b/pkg/services/dns_service.go @@ -92,9 +92,11 @@ func (s *DNSService) GetComposeConfig() (*types.Config, error) { return &types.Config{Services: services}, nil } -// WriteConfig generates a Corefile for DNS setup by retrieving the project root, -// domain, and service IPs. It includes DNS records, templates the Corefile, -// ensures directory existence, and writes the file. +// WriteConfig generates a Corefile for DNS configuration by gathering project root, TLD, and service IPs, +// constructing DNS host entries, and appending static DNS records. It adapts the Corefile for localhost +// by adding a template for local DNS resolution. Additionally, it configures DNS forwarding by including +// specified forward addresses, ensuring DNS queries are directed appropriately. The final Corefile is +// written to the .windsor config directory func (s *DNSService) WriteConfig() error { projectRoot, err := s.shell.GetProjectRoot() if err != nil { @@ -125,15 +127,38 @@ func (s *DNSService) WriteConfig() error { hostEntries += fmt.Sprintf(" %s\n", record) } - corefileContent := fmt.Sprintf(` + forwardAddresses := s.configHandler.GetStringSlice("dns.forward", nil) + if len(forwardAddresses) == 0 { + forwardAddresses = []string{"1.1.1.1", "8.8.8.8"} + } + forwardAddressesStr := fmt.Sprintf("%s", forwardAddresses[0]) + for _, addr := range forwardAddresses[1:] { + forwardAddressesStr += fmt.Sprintf(" %s", addr) + } + + var corefileContent string + if s.IsLocalhost() { + corefileContent = fmt.Sprintf(` +%s:53 { + template IN A { + match .*\.%s + answer "{{ .Name }} 60 IN A 127.0.0.1" + } + + forward . %s +} +`, tld, tld, forwardAddressesStr) + } else { + corefileContent = fmt.Sprintf(` %s:53 { hosts { %s fallthrough } - forward . 1.1.1.1 8.8.8.8 + forward . %s } -`, tld, hostEntries) +`, tld, hostEntries, forwardAddressesStr) + } corefilePath := filepath.Join(projectRoot, ".windsor", "Corefile") diff --git a/pkg/services/dns_service_test.go b/pkg/services/dns_service_test.go index 1bfbff7d7..9dce967ef 100644 --- a/pkg/services/dns_service_test.go +++ b/pkg/services/dns_service_test.go @@ -34,15 +34,21 @@ func createDNSServiceMocks(mockInjector ...di.Injector) *MockComponents { }, DNS: &dns.DNSConfig{ Enabled: &enabled, - Domain: ptrString("test1"), - Records: []string{"127.0.0.1 test1", "192.168.1.1 test1"}, + Domain: ptrString("test"), + Records: []string{"127.0.0.1 test", "192.168.1.1 test"}, }, } } + mockConfigHandler.GetConfigRootFunc = func() (string, error) { + return filepath.FromSlash("/invalid/path"), nil + } + mockConfigHandler.GetContextFunc = func() string { + return "test-context" + } mockConfigHandler.GetStringSliceFunc = func(key string, defaultValue ...[]string) []string { if key == "dns.records" { - return []string{"127.0.0.1 test1", "192.168.1.1 test1"} + return []string{"127.0.0.1 test", "192.168.1.1 test"} } if len(defaultValue) > 0 { return defaultValue[0] @@ -67,6 +73,16 @@ func createDNSServiceMocks(mockInjector ...di.Injector) *MockComponents { injector.Register("configHandler", mockConfigHandler) injector.Register("shell", mockShell) + // Mock the writeFile function to avoid writing to the real file system + writeFile = func(filename string, data []byte, perm os.FileMode) error { + return nil + } + + // Mock the mkdirAll function to avoid creating directories in the real file system + mkdirAll = func(path string, perm os.FileMode) error { + return nil + } + return &MockComponents{ Injector: injector, MockConfigHandler: mockConfigHandler, @@ -304,28 +320,6 @@ func TestDNSService_WriteConfig(t *testing.T) { t.Run("Success", func(t *testing.T) { // Create mocks and set up the mock context mocks := createDNSServiceMocks() - mocks.MockConfigHandler.GetConfigRootFunc = func() (string, error) { - return "/mock/config/root", nil - } - mocks.MockConfigHandler.GetContextFunc = func() string { - return "test" - } - - // Configure the mock config handler to return Docker enabled - mocks.MockConfigHandler.GetConfigFunc = func() *v1alpha1.Context { - return &v1alpha1.Context{ - Docker: &docker.DockerConfig{ - Enabled: ptrBool(true), - Registries: map[string]docker.RegistryConfig{ - "service1": {Remote: "remote1", Local: "local1"}, - "service2": {Remote: "remote2", Local: "local2"}, - }, - }, - DNS: &dns.DNSConfig{ - Enabled: ptrBool(true), - }, - } - } // Given: a DNSService with the mock config handler, context, and real DockerService service := NewDNSService(mocks.Injector) @@ -335,13 +329,57 @@ func TestDNSService_WriteConfig(t *testing.T) { t.Fatalf("Initialize() error = %v", err) } - // Mock the writeFile function to avoid writing to the real file system + // Mock the writeFile function to capture the content written + var writtenContent []byte writeFile = func(filename string, data []byte, perm os.FileMode) error { + writtenContent = data return nil } - // Mock the mkdirAll function to avoid creating directories in the real file system - mkdirAll = func(path string, perm os.FileMode) error { + // When: WriteConfig is called + err := service.WriteConfig() + + // Then: no error should be returned + if err != nil { + t.Fatalf("WriteConfig() error = %v", err) + } + + // Verify that the Corefile content is correctly formatted + expectedCorefileContent := ` +test:53 { + hosts { + 127.0.0.1 test + 192.168.1.1 test + fallthrough + } + + forward . 1.1.1.1 8.8.8.8 +} +` + if string(writtenContent) != expectedCorefileContent { + t.Errorf("Expected Corefile content:\n%s\nGot:\n%s", expectedCorefileContent, string(writtenContent)) + } + }) + + t.Run("SuccessLocalhost", func(t *testing.T) { + // Create mocks and set up the mock context + mocks := createDNSServiceMocks() + + // Given: a DNSService with the mock config handler, context, and real DockerService + service := NewDNSService(mocks.Injector) + + // Initialize the service + if err := service.Initialize(); err != nil { + t.Fatalf("Initialize() error = %v", err) + } + + // Set the address to localhost to mock IsLocalhost behavior + service.SetAddress("127.0.0.1") + + // Mock the writeFile function to capture the content written + var writtenContent []byte + writeFile = func(filename string, data []byte, perm os.FileMode) error { + writtenContent = data return nil } @@ -352,6 +390,21 @@ func TestDNSService_WriteConfig(t *testing.T) { if err != nil { t.Fatalf("WriteConfig() error = %v", err) } + + // Verify that the Corefile content is correctly formatted for localhost + expectedCorefileContent := ` +test:53 { + template IN A { + match .*\.test + answer "{{ .Name }} 60 IN A 127.0.0.1" + } + + forward . 1.1.1.1 8.8.8.8 +} +` + if string(writtenContent) != expectedCorefileContent { + t.Errorf("Expected Corefile content:\n%s\nGot:\n%s", expectedCorefileContent, string(writtenContent)) + } }) t.Run("ErrorRetrievingProjectRoot", func(t *testing.T) { @@ -383,22 +436,6 @@ func TestDNSService_WriteConfig(t *testing.T) { t.Run("ValidAddress", func(t *testing.T) { // Create a mock context and config handler mocks := createDNSServiceMocks() - mocks.MockConfigHandler.GetConfigRootFunc = func() (string, error) { - return "/mock/config/root", nil - } - - // Create a mock config handler that returns Docker and DNS enabled - mocks.MockConfigHandler.GetConfigFunc = func() *v1alpha1.Context { - return &v1alpha1.Context{ - Docker: &docker.DockerConfig{ - Enabled: ptrBool(true), - }, - DNS: &dns.DNSConfig{ - Enabled: ptrBool(true), - Domain: ptrString("test"), - }, - } - } // Create a mock service that returns a valid address mockService := NewMockService() @@ -425,16 +462,6 @@ func TestDNSService_WriteConfig(t *testing.T) { t.Fatalf("Initialize() error = %v", err) } - // Mock the writeFile function to avoid writing to the real file system - writeFile = func(filename string, data []byte, perm os.FileMode) error { - return nil - } - - // Mock the mkdirAll function to avoid creating directories in the real file system - mkdirAll = func(path string, perm os.FileMode) error { - return nil - } - // When: WriteConfig is called err := service.WriteConfig() @@ -447,23 +474,6 @@ func TestDNSService_WriteConfig(t *testing.T) { t.Run("ErrorWritingCorefile", func(t *testing.T) { // Mock the GetConfigRoot function to return a mock path mocks := createDNSServiceMocks() - mocks.MockConfigHandler.GetConfigRootFunc = func() (string, error) { - return "/mock/config/root", nil - } - - // Create a mock config handler that returns Docker enabled - mocks.MockConfigHandler.GetConfigFunc = func() *v1alpha1.Context { - return &v1alpha1.Context{ - Docker: &docker.DockerConfig{ - Enabled: ptrBool(true), - }, - DNS: &dns.DNSConfig{ - Enabled: ptrBool(true), - }, - } - } - - mocks.Injector.Register("dockerService", NewMockService()) // Given: a DNSService with the mock config handler, context, and DockerService service := NewDNSService(mocks.Injector) @@ -488,6 +498,9 @@ func TestDNSService_WriteConfig(t *testing.T) { }) t.Run("MkdirAllError", func(t *testing.T) { + // Setup injector with mocks + mocks := createDNSServiceMocks() + // Save the original mkdirAll function originalMkdirAll := mkdirAll @@ -501,30 +514,6 @@ func TestDNSService_WriteConfig(t *testing.T) { mkdirAll = originalMkdirAll }() - // Setup injector with mocks - mocks := createDNSServiceMocks() - - // Mock the configHandler - mocks.MockConfigHandler.GetConfigFunc = func() *v1alpha1.Context { - // Return a context config where Docker is enabled - return &v1alpha1.Context{ - Docker: &docker.DockerConfig{ - Enabled: ptrBool(true), - }, - DNS: &dns.DNSConfig{ - Enabled: ptrBool(true), - }, - } - } - - // Mock the context - mocks.MockConfigHandler.GetConfigRootFunc = func() (string, error) { - return filepath.FromSlash("/invalid/path"), nil - } - mocks.MockConfigHandler.GetContextFunc = func() string { - return "test-context" - } - // Create the DNSService instance service := NewDNSService(mocks.Injector) diff --git a/pkg/services/talos_service.go b/pkg/services/talos_service.go index 4be13f928..866ffa3a5 100644 --- a/pkg/services/talos_service.go +++ b/pkg/services/talos_service.go @@ -91,22 +91,22 @@ func (s *TalosService) SetAddress(address string) error { return err } - nodePorts := s.configHandler.GetStringSlice(fmt.Sprintf("cluster.%s.nodeports", nodeType), []string{}) + hostPorts := s.configHandler.GetStringSlice(fmt.Sprintf("cluster.%s.hostports", nodeType), []string{}) - nodePortsCopy := make([]string, len(nodePorts)) - copy(nodePortsCopy, nodePorts) + hostPortsCopy := make([]string, len(hostPorts)) + copy(hostPortsCopy, hostPorts) - for i := 0; i < len(nodePortsCopy); i++ { - parts := strings.Split(nodePortsCopy[i], ":") + for i := 0; i < len(hostPortsCopy); i++ { + parts := strings.Split(hostPortsCopy[i], ":") var hostPort, nodePort int protocol := "tcp" switch len(parts) { - case 1: // nodePort only + case 1: // hostPort only var err error nodePort, err = strconv.Atoi(parts[0]) if err != nil { - return fmt.Errorf("invalid nodePort value: %s", parts[0]) + return fmt.Errorf("invalid hostPort value: %s", parts[0]) } hostPort = nodePort case 2: // hostPort and nodePort/protocol @@ -118,7 +118,7 @@ func (s *TalosService) SetAddress(address string) error { nodePortProtocol := strings.Split(parts[1], "/") nodePort, err = strconv.Atoi(nodePortProtocol[0]) if err != nil { - return fmt.Errorf("invalid nodePort value: %s", nodePortProtocol[0]) + return fmt.Errorf("invalid hostPort value: %s", nodePortProtocol[0]) } if len(nodePortProtocol) == 2 { if nodePortProtocol[1] == "tcp" || nodePortProtocol[1] == "udp" { @@ -128,7 +128,7 @@ func (s *TalosService) SetAddress(address string) error { } } default: - return fmt.Errorf("invalid nodePort format: %s", nodePortsCopy[i]) + return fmt.Errorf("invalid hostPort format: %s", hostPortsCopy[i]) } // Check for conflicts in hostPort @@ -137,10 +137,10 @@ func (s *TalosService) SetAddress(address string) error { } usedHostPorts[hostPort] = true - nodePortsCopy[i] = fmt.Sprintf("%d:%d/%s", hostPort, nodePort, protocol) + hostPortsCopy[i] = fmt.Sprintf("%d:%d/%s", hostPort, nodePort, protocol) } - if err := s.configHandler.SetContextValue(fmt.Sprintf("cluster.%s.nodes.%s.nodeports", nodeType, s.name), nodePortsCopy); err != nil { + if err := s.configHandler.SetContextValue(fmt.Sprintf("cluster.%s.nodes.%s.hostports", nodeType, s.name), hostPortsCopy); err != nil { return err } @@ -261,10 +261,10 @@ func (s *TalosService) GetComposeConfig() (*types.Config, error) { } } - nodePortsKey := fmt.Sprintf("cluster.%s.nodes.%s.nodeports", nodeType, nodeName) - nodePorts := s.configHandler.GetStringSlice(nodePortsKey) - for _, nodePortStr := range nodePorts { - parts := strings.Split(nodePortStr, ":") + hostPortsKey := fmt.Sprintf("cluster.%s.nodes.%s.hostports", nodeType, nodeName) + hostPorts := s.configHandler.GetStringSlice(hostPortsKey) + for _, hostPortStr := range hostPorts { + parts := strings.Split(hostPortStr, ":") hostPort, err := strconv.ParseUint(parts[0], 10, 32) if err != nil || hostPort > math.MaxUint32 { return nil, fmt.Errorf("invalid hostPort value: %s", parts[0]) @@ -272,7 +272,7 @@ func (s *TalosService) GetComposeConfig() (*types.Config, error) { nodePortProtocol := strings.Split(parts[1], "/") nodePort, err := strconv.ParseUint(nodePortProtocol[0], 10, 32) if err != nil || nodePort > math.MaxUint32 { - return nil, fmt.Errorf("invalid nodePort value: %s", nodePortProtocol[0]) + return nil, fmt.Errorf("invalid hostPort value: %s", nodePortProtocol[0]) } protocol := "tcp" if len(nodePortProtocol) == 2 { diff --git a/pkg/services/talos_service_test.go b/pkg/services/talos_service_test.go index 2b51445f4..db5e28a9c 100644 --- a/pkg/services/talos_service_test.go +++ b/pkg/services/talos_service_test.go @@ -66,11 +66,11 @@ func setupTalosServiceMocks(optionalInjector ...di.Injector) *MockComponents { mockConfigHandler.GetStringSliceFunc = func(key string, defaultValue ...[]string) []string { switch key { - case "cluster.workers.nodes.worker1.nodeports": + case "cluster.workers.nodes.worker1.hostports": return []string{"30000:30000", "30001:30001/udp"} - case "cluster.workers.nodes.worker2.nodeports": + case "cluster.workers.nodes.worker2.hostports": return []string{"30002:30002/tcp", "30003:30003"} - case "cluster.workers.nodeports": + case "cluster.workers.hostports": return []string{"30000:30000", "30001:30001/udp", "30002:30002/tcp", "30003:30003"} default: if len(defaultValue) > 0 { @@ -88,13 +88,13 @@ func setupTalosServiceMocks(optionalInjector ...di.Injector) *MockComponents { CPU *int `yaml:"cpu,omitempty"` Memory *int `yaml:"memory,omitempty"` Nodes map[string]cluster.NodeConfig `yaml:"nodes,omitempty"` - NodePorts []string `yaml:"nodeports,omitempty"` + HostPorts []string `yaml:"hostports,omitempty"` }{ Nodes: map[string]cluster.NodeConfig{ "worker1": {}, "worker2": {}, }, - NodePorts: []string{"30000:30000/tcp", "30001:30001/udp", "30002:30002/tcp", "30003:30003/udp"}, + HostPorts: []string{"30000:30000/tcp", "30001:30001/udp", "30002:30002/tcp", "30003:30003/udp"}, }, }, } @@ -351,7 +351,7 @@ func TestTalosService_SetAddress(t *testing.T) { } }) - t.Run("ErrorSettingNodePorts", func(t *testing.T) { + t.Run("ErrorSettingHostPorts", func(t *testing.T) { // Setup mocks for this test mocks := setupTalosServiceMocks() service := NewTalosService(mocks.Injector, "worker") @@ -361,10 +361,10 @@ func TestTalosService_SetAddress(t *testing.T) { t.Fatalf("expected no error during initialization, got %v", err) } - // Simulate an error when setting node ports with non-integer values + // Simulate an error when setting host ports with non-integer values mocks.MockConfigHandler.SetContextValueFunc = func(key string, value interface{}) error { - if key == "cluster.workers.nodes."+service.name+".nodeports" { - return fmt.Errorf("mock error setting node ports") + if key == "cluster.workers.nodes."+service.name+".hostports" { + return fmt.Errorf("mock error setting host ports") } return nil } @@ -372,58 +372,58 @@ func TestTalosService_SetAddress(t *testing.T) { // Attempt to set the address, expecting an error if err := service.SetAddress("localhost"); err == nil { t.Fatalf("expected an error, got nil") - } else if err.Error() != "mock error setting node ports" { - t.Fatalf("expected error message 'mock error setting node ports', got %v", err) + } else if err.Error() != "mock error setting host ports" { + t.Fatalf("expected error message 'mock error setting host ports', got %v", err) } }) - t.Run("NodePortValidation", func(t *testing.T) { + t.Run("HostPortValidation", func(t *testing.T) { tests := []struct { name string - nodePorts []string + hostPorts []string expectedError string expectSuccess bool }{ { - name: "NodePortOnly", - nodePorts: []string{"30000"}, + name: "HostPortOnly", + hostPorts: []string{"30000"}, expectedError: "", expectSuccess: true, }, { - name: "InvalidSingleNodePort", - nodePorts: []string{"abc"}, - expectedError: "invalid nodePort value: abc", + name: "InvalidSingleHostPort", + hostPorts: []string{"abc"}, + expectedError: "invalid hostPort value: abc", expectSuccess: false, }, { - name: "InvalidNodePortFormat", - nodePorts: []string{"abc:123"}, + name: "InvalidHostPortFormat", + hostPorts: []string{"abc:123"}, expectedError: "invalid hostPort value: abc", expectSuccess: false, }, { - name: "NonIntegerNodePort", - nodePorts: []string{"123:abc"}, - expectedError: "invalid nodePort value: abc", + name: "NonIntegerHostPort", + hostPorts: []string{"123:abc"}, + expectedError: "invalid hostPort value: abc", expectSuccess: false, }, { - name: "ValidNodePort", - nodePorts: []string{"8080:80/tcp"}, + name: "ValidHostPort", + hostPorts: []string{"8080:80/tcp"}, expectedError: "", expectSuccess: true, }, { name: "InvalidProtocol", - nodePorts: []string{"8080:80/http"}, + hostPorts: []string{"8080:80/http"}, expectedError: "invalid protocol value: http", expectSuccess: false, }, { - name: "IncorrectNodePortFormat", - nodePorts: []string{"8080:80:tcp"}, - expectedError: "invalid nodePort format: 8080:80:tcp", + name: "IncorrectHostPortFormat", + hostPorts: []string{"8080:80:tcp"}, + expectedError: "invalid hostPort format: 8080:80:tcp", expectSuccess: false, }, } @@ -439,10 +439,10 @@ func TestTalosService_SetAddress(t *testing.T) { t.Fatalf("expected no error during initialization, got %v", err) } - // Simulate node port configuration + // Simulate host port configuration mocks.MockConfigHandler.GetStringSliceFunc = func(key string, defaultValue ...[]string) []string { - if key == "cluster.workers.nodeports" { - return tt.nodePorts + if key == "cluster.workers.hostports" { + return tt.hostPorts } if len(defaultValue) > 0 { return defaultValue[0] @@ -755,7 +755,7 @@ func TestTalosService_GetComposeConfig(t *testing.T) { // Mock the GetStringSlice method to return an invalid host port mocks.MockConfigHandler.GetStringSliceFunc = func(key string, defaultValue ...[]string) []string { - if key == "cluster.workers.nodes.worker.nodeports" { + if key == "cluster.workers.nodes.worker.hostports" { return []string{"invalidPort:30000/tcp"} } return nil @@ -779,15 +779,15 @@ func TestTalosService_GetComposeConfig(t *testing.T) { } }) - t.Run("InvalidNodePort", func(t *testing.T) { + t.Run("InvalidHostPort", func(t *testing.T) { // Setup mocks for this test mocks := setupTalosServiceMocks() service := NewTalosService(mocks.Injector, "worker") - // Mock the GetStringSlice method to return an invalid node port + // Mock the GetStringSlice method to return an invalid host port mocks.MockConfigHandler.GetStringSliceFunc = func(key string, defaultValue ...[]string) []string { - if key == "cluster.workers.nodes.worker.nodeports" { - return []string{"30000:invalidNodePort/tcp"} + if key == "cluster.workers.nodes.worker.hostports" { + return []string{"30000:invalidHostPort/tcp"} } return nil } @@ -803,10 +803,10 @@ func TestTalosService_GetComposeConfig(t *testing.T) { // Then an error should be returned if err == nil { - t.Fatalf("expected an error due to invalid node port, got nil") + t.Fatalf("expected an error due to invalid host port, got nil") } - if err.Error() != "invalid nodePort value: invalidNodePort" { - t.Fatalf("expected error message 'invalid nodePort value: invalidNodePort', got %v", err) + if err.Error() != "invalid hostPort value: invalidHostPort" { + t.Fatalf("expected error message 'invalid hostPort value: invalidHostPort', got %v", err) } }) @@ -815,9 +815,9 @@ func TestTalosService_GetComposeConfig(t *testing.T) { mocks := setupTalosServiceMocks() service := NewTalosService(mocks.Injector, "worker") - // Mock the GetStringSlice method to return a valid node port configuration + // Mock the GetStringSlice method to return a valid host port configuration mocks.MockConfigHandler.GetStringSliceFunc = func(key string, defaultValue ...[]string) []string { - if key == "cluster.workers.nodes.worker.nodeports" { + if key == "cluster.workers.nodes.worker.hostports" { return []string{"30000:30000/tcp"} } return nil