diff --git a/examples/local-config.yaml b/examples/local-config.yaml index 5e2ddc7..179f3a8 100644 --- a/examples/local-config.yaml +++ b/examples/local-config.yaml @@ -14,6 +14,20 @@ cluster: worker: kubernetes.io/os: linux + # Storage class for persistent volumes (default: "standard") + # Use "local-path" for k3s clusters + # storage_class: local-path + + # HTTPS port for Gateway listener (default: 443) + # Override if 443 is already in use or requires root + # https_port: 8443 + + # MetalLB configuration (default: enabled with 192.168.1.100-192.168.1.110 pool) + # Disable for k3s which ships with ServiceLB + # metallb: + # enabled: false + # address_pool: 172.18.255.100-172.18.255.110 + # GitOps repository configuration (optional) # Configures the repository that ArgoCD will use to manage cluster resources # diff --git a/pkg/provider/local/config.go b/pkg/provider/local/config.go index bb65ce6..600ffed 100644 --- a/pkg/provider/local/config.go +++ b/pkg/provider/local/config.go @@ -1,8 +1,22 @@ package local -// Config represents local K3s configuration +// Config represents local provider configuration type Config struct { KubeContext string `yaml:"kube_context,omitempty"` NodeSelectors map[string]map[string]string `yaml:"node_selectors,omitempty"` + StorageClass string `yaml:"storage_class,omitempty"` + HTTPSPort int `yaml:"https_port,omitempty"` + MetalLB *MetalLBConfig `yaml:"metallb,omitempty"` AdditionalFields map[string]any `yaml:",inline"` } + +// MetalLBConfig holds MetalLB-specific settings for the local provider. +type MetalLBConfig struct { + // Enabled controls whether MetalLB is deployed. Default: true. + // Use a pointer to distinguish "not set" (default true) from "explicitly false". + Enabled *bool `yaml:"enabled,omitempty"` + + // AddressPool is the IP range for MetalLB's IPAddressPool. + // Default: "192.168.1.100-192.168.1.110" + AddressPool string `yaml:"address_pool,omitempty"` +} diff --git a/pkg/provider/local/provider.go b/pkg/provider/local/provider.go index 594fc71..1a25440 100644 --- a/pkg/provider/local/provider.go +++ b/pkg/provider/local/provider.go @@ -267,11 +267,42 @@ func (p *Provider) Summary(clusterConfig *config.ClusterConfig) map[string]strin } // InfraSettings returns local provider Kubernetes infrastructure settings. -func (p *Provider) InfraSettings(_ *config.ClusterConfig) provider.InfraSettings { - return provider.InfraSettings{ +// Values are read from the local provider config block, falling back to defaults. +// Parse errors are intentionally ignored: InfraSettings is called after Validate() +// has confirmed the config is parseable. If it somehow fails (e.g., nil config in +// tests), we return valid defaults. +func (p *Provider) InfraSettings(cfg *config.ClusterConfig) provider.InfraSettings { + settings := provider.InfraSettings{ StorageClass: "standard", NeedsMetalLB: true, MetalLBAddressPool: "192.168.1.100-192.168.1.110", SupportsLocalGitOps: true, } + + rawCfg := cfg.ProviderConfig() + if rawCfg == nil { + return settings + } + + var localCfg Config + if err := config.UnmarshalProviderConfig(context.Background(), rawCfg, &localCfg); err != nil { + return settings + } + + if localCfg.StorageClass != "" { + settings.StorageClass = localCfg.StorageClass + } + if localCfg.HTTPSPort != 0 { + settings.HTTPSPort = localCfg.HTTPSPort + } + if localCfg.MetalLB != nil { + if localCfg.MetalLB.Enabled != nil { + settings.NeedsMetalLB = *localCfg.MetalLB.Enabled + } + if localCfg.MetalLB.AddressPool != "" { + settings.MetalLBAddressPool = localCfg.MetalLB.AddressPool + } + } + + return settings } diff --git a/pkg/provider/local/provider_test.go b/pkg/provider/local/provider_test.go index 5d24582..b66968a 100644 --- a/pkg/provider/local/provider_test.go +++ b/pkg/provider/local/provider_test.go @@ -12,29 +12,135 @@ var _ provider.Provider = (*Provider)(nil) func TestInfraSettings(t *testing.T) { p := NewProvider() - cfg := &config.ClusterConfig{ - Providers: map[string]any{"local": map[string]any{}}, - } - - settings := p.InfraSettings(cfg) tests := []struct { - name string - got any - want any + name string + providerConfig map[string]any + wantSC string + wantMetalLB bool + wantPool string + wantHTTPSPort int }{ - {"StorageClass", settings.StorageClass, "standard"}, - {"NeedsMetalLB", settings.NeedsMetalLB, true}, - {"MetalLBAddressPool", settings.MetalLBAddressPool, "192.168.1.100-192.168.1.110"}, - {"LoadBalancerAnnotations is empty", len(settings.LoadBalancerAnnotations), 0}, - {"KeycloakBasePath is empty", settings.KeycloakBasePath, ""}, - {"SupportsLocalGitOps", settings.SupportsLocalGitOps, true}, + { + name: "no local config block returns defaults", + providerConfig: nil, + wantSC: "standard", + wantMetalLB: true, + wantPool: "192.168.1.100-192.168.1.110", + wantHTTPSPort: 0, + }, + { + name: "empty local config returns defaults", + providerConfig: map[string]any{"local": map[string]any{}}, + wantSC: "standard", + wantMetalLB: true, + wantPool: "192.168.1.100-192.168.1.110", + wantHTTPSPort: 0, + }, + { + name: "storage_class override", + providerConfig: map[string]any{ + "local": map[string]any{"storage_class": "local-path"}, + }, + wantSC: "local-path", + wantMetalLB: true, + wantPool: "192.168.1.100-192.168.1.110", + wantHTTPSPort: 0, + }, + { + name: "metallb disabled", + providerConfig: map[string]any{ + "local": map[string]any{ + "metallb": map[string]any{"enabled": false}, + }, + }, + wantSC: "standard", + wantMetalLB: false, + wantPool: "192.168.1.100-192.168.1.110", + wantHTTPSPort: 0, + }, + { + name: "metallb address_pool override", + providerConfig: map[string]any{ + "local": map[string]any{ + "metallb": map[string]any{ + "address_pool": "172.18.255.100-172.18.255.110", + }, + }, + }, + wantSC: "standard", + wantMetalLB: true, + wantPool: "172.18.255.100-172.18.255.110", + wantHTTPSPort: 0, + }, + { + name: "https_port override", + providerConfig: map[string]any{ + "local": map[string]any{"https_port": 8443}, + }, + wantSC: "standard", + wantMetalLB: true, + wantPool: "192.168.1.100-192.168.1.110", + wantHTTPSPort: 8443, + }, + { + name: "full override", + providerConfig: map[string]any{ + "local": map[string]any{ + "storage_class": "local-path", + "https_port": 8443, + "metallb": map[string]any{ + "enabled": false, + "address_pool": "10.0.0.100-10.0.0.110", + }, + }, + }, + wantSC: "local-path", + wantMetalLB: false, + wantPool: "10.0.0.100-10.0.0.110", + wantHTTPSPort: 8443, + }, + { + name: "unmarshal error returns defaults", + providerConfig: map[string]any{ + "local": "not-a-map", + }, + wantSC: "standard", + wantMetalLB: true, + wantPool: "192.168.1.100-192.168.1.110", + wantHTTPSPort: 0, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if tt.got != tt.want { - t.Errorf("got %v, want %v", tt.got, tt.want) + cfg := &config.ClusterConfig{ + Providers: tt.providerConfig, + } + + settings := p.InfraSettings(cfg) + + if settings.StorageClass != tt.wantSC { + t.Errorf("StorageClass = %q, want %q", settings.StorageClass, tt.wantSC) + } + if settings.NeedsMetalLB != tt.wantMetalLB { + t.Errorf("NeedsMetalLB = %v, want %v", settings.NeedsMetalLB, tt.wantMetalLB) + } + if settings.MetalLBAddressPool != tt.wantPool { + t.Errorf("MetalLBAddressPool = %q, want %q", settings.MetalLBAddressPool, tt.wantPool) + } + if settings.HTTPSPort != tt.wantHTTPSPort { + t.Errorf("HTTPSPort = %d, want %d", settings.HTTPSPort, tt.wantHTTPSPort) + } + // Fields not set by local provider should always be zero values + if len(settings.LoadBalancerAnnotations) != 0 { + t.Errorf("LoadBalancerAnnotations = %v, want empty", settings.LoadBalancerAnnotations) + } + if settings.KeycloakBasePath != "" { + t.Errorf("KeycloakBasePath = %q, want empty", settings.KeycloakBasePath) + } + if !settings.SupportsLocalGitOps { + t.Error("SupportsLocalGitOps = false, want true") } }) }