diff --git a/csil/v1/components/k3s.csil b/csil/v1/components/k3s.csil index 870d0f9..882ac0f 100644 --- a/csil/v1/components/k3s.csil +++ b/csil/v1/components/k3s.csil @@ -22,6 +22,7 @@ Config = { server_url: text @go_name("ServerURL"), dns_servers: [* text] @go_name("DNSServers"), ? additional_registries: [* AdditionalRegistry] @go_name("AdditionalRegistries"), +? etcd_args: [* text] @go_name("EtcdArgs"), ? allow_cgnat_vip: bool @go_name("AllowCGNATVIP"), } diff --git a/docs/tailscale-integration.md b/docs/tailscale-integration.md index 75a4059..d85c87d 100644 --- a/docs/tailscale-integration.md +++ b/docs/tailscale-integration.md @@ -268,4 +268,4 @@ Future enhancements planned for Tailscale integration: ## Contributing -Found an issue or have suggestions for Tailscale integration? Please open an issue on the [Foundry GitHub repository](https://github.com/catalystcommunity/foundry). +Found an issue or have suggestions for Tailscale integration? Please open an issue on the [Foundry GitHub repository](https://github.com/catalystcommunity/foundry). \ No newline at end of file diff --git a/v1/internal/component/k3s/types.go b/v1/internal/component/k3s/types.go index 1f2c7a8..caf0b5a 100644 --- a/v1/internal/component/k3s/types.go +++ b/v1/internal/component/k3s/types.go @@ -64,6 +64,11 @@ func ParseConfig(cfg component.ComponentConfig) (*Config, error) { config.VIP = vip } + // Allow CGNAT VIP + if allowCGNAT, ok := cfg.GetBool("allow_cgnat_vip"); ok { + config.AllowCGNATVIP = &allowCGNAT + } + // Interface if iface, ok := cfg.GetString("interface"); ok { config.Interface = iface diff --git a/v1/internal/component/k3s/vip.go b/v1/internal/component/k3s/vip.go index 2d25e00..3202c47 100644 --- a/v1/internal/component/k3s/vip.go +++ b/v1/internal/component/k3s/vip.go @@ -57,9 +57,9 @@ func ValidateVIP(vip string, allowCGNAT bool) error { // isPrivateIP checks if an IP is in private ranges (RFC1918) or optionally shared address space (RFC6598) func isPrivateIP(ip net.IP, allowCGNAT bool) bool { private := []string{ - "10.0.0.0/8", // RFC1918 - Private-Use - "172.16.0.0/12", // RFC1918 - Private-Use - "192.168.0.0/16", // RFC1918 - Private-Use + "10.0.0.0/8", // RFC1918 - Private-Use + "172.16.0.0/12", // RFC1918 - Private-Use + "192.168.0.0/16", // RFC1918 - Private-Use } // Optionally include CGNAT range (RFC6598) used by Tailscale and similar overlay networks diff --git a/v1/internal/component/k3s/vip_test.go b/v1/internal/component/k3s/vip_test.go index e743576..319ac81 100644 --- a/v1/internal/component/k3s/vip_test.go +++ b/v1/internal/component/k3s/vip_test.go @@ -212,8 +212,9 @@ func TestDetermineVIPConfig(t *testing.T) { } }, want: &VIPConfig{ - VIP: "192.168.1.100", - Interface: "eth0", + VIP: "192.168.1.100", + Interface: "eth0", + AllowCGNATVIP: func() *bool { v := false; return &v }(), }, wantErr: false, }, diff --git a/v1/internal/config/types.gen.go b/v1/internal/config/types.gen.go index 5def5de..322a8f7 100644 --- a/v1/internal/config/types.gen.go +++ b/v1/internal/config/types.gen.go @@ -4,46 +4,46 @@ package config import ( - "github.com/catalystcommunity/foundry/v1/internal/setup" "github.com/catalystcommunity/foundry/v1/internal/host" + "github.com/catalystcommunity/foundry/v1/internal/setup" ) // NetworkConfig represents a structured data type type NetworkConfig struct { - Gateway string `json:"gateway" yaml:"gateway"` - Netmask string `json:"netmask" yaml:"netmask"` + Gateway string `json:"gateway" yaml:"gateway"` + Netmask string `json:"netmask" yaml:"netmask"` DHCPRange *DHCPRange `json:"dhcp_range,omitempty" yaml:"dhcp_range,omitempty"` } // DHCPRange represents a structured data type type DHCPRange struct { Start string `json:"start" yaml:"start"` - End string `json:"end" yaml:"end"` + End string `json:"end" yaml:"end"` } // DNSConfig represents a structured data type type DNSConfig struct { InfrastructureZones []DNSZone `json:"infrastructure_zones" yaml:"infrastructure_zones"` - KubernetesZones []DNSZone `json:"kubernetes_zones" yaml:"kubernetes_zones"` - Forwarders []string `json:"forwarders" yaml:"forwarders"` - Backend string `json:"backend" yaml:"backend"` - APIKey string `json:"api_key" yaml:"api_key"` + KubernetesZones []DNSZone `json:"kubernetes_zones" yaml:"kubernetes_zones"` + Forwarders []string `json:"forwarders" yaml:"forwarders"` + Backend string `json:"backend" yaml:"backend"` + APIKey string `json:"api_key" yaml:"api_key"` } // DNSZone represents a structured data type type DNSZone struct { - Name string `json:"name" yaml:"name"` - Public bool `json:"public" yaml:"public"` + Name string `json:"name" yaml:"name"` + Public bool `json:"public" yaml:"public"` PublicCNAME *string `json:"public_cname,omitempty" yaml:"public_cname,omitempty"` } // ClusterConfig represents a structured data type type ClusterConfig struct { - Name string `json:"name" yaml:"name"` - Domain *string `json:"domain,omitempty" yaml:"domain,omitempty"` - PrimaryDomain string `json:"primary_domain" yaml:"primary_domain"` - VIP string `json:"vip" yaml:"vip"` - AllowCGNATVIP *bool `json:"allow_cgnat_vip,omitempty" yaml:"allow_cgnat_vip,omitempty"` + Name string `json:"name" yaml:"name"` + Domain *string `json:"domain,omitempty" yaml:"domain,omitempty"` + PrimaryDomain string `json:"primary_domain" yaml:"primary_domain"` + VIP string `json:"vip" yaml:"vip"` + AllowCGNATVIP *bool `json:"allow_cgnat_vip,omitempty" yaml:"allow_cgnat_vip,omitempty"` } // ComponentMap is a type alias @@ -51,16 +51,16 @@ type ComponentMap map[string]ComponentConfig // ComponentConfig represents a structured data type type ComponentConfig struct { - Version *string `json:"version,omitempty" yaml:"version,omitempty"` - Hosts []string `json:"hosts,omitempty" yaml:"hosts,omitempty"` - Config map[string]any `json:"config" yaml:",inline"` + Version *string `json:"version,omitempty" yaml:"version,omitempty"` + Hosts []string `json:"hosts,omitempty" yaml:"hosts,omitempty"` + Config map[string]any `json:"config" yaml:",inline"` } // ObsConfig represents a structured data type type ObsConfig struct { Prometheus *PrometheusConfig `json:"prometheus,omitempty" yaml:"prometheus,omitempty"` - Loki *LokiConfig `json:"loki,omitempty" yaml:"loki,omitempty"` - Grafana *GrafanaConfig `json:"grafana,omitempty" yaml:"grafana,omitempty"` + Loki *LokiConfig `json:"loki,omitempty" yaml:"loki,omitempty"` + Grafana *GrafanaConfig `json:"grafana,omitempty" yaml:"grafana,omitempty"` } // PrometheusConfig represents a structured data type @@ -80,7 +80,7 @@ type GrafanaConfig struct { // StorageConfig represents a structured data type type StorageConfig struct { - Backend string `json:"backend" yaml:"backend"` + Backend string `json:"backend" yaml:"backend"` TrueNAS *TrueNASConfig `json:"truenas,omitempty" yaml:"truenas,omitempty"` } @@ -92,13 +92,12 @@ type TrueNASConfig struct { // Config represents a structured data type type Config struct { - Network *NetworkConfig `json:"network,omitempty" yaml:"network,omitempty"` - DNS *DNSConfig `json:"dns,omitempty" yaml:"dns,omitempty"` - Cluster ClusterConfig `json:"cluster" yaml:"cluster"` - Components ComponentMap `json:"components" yaml:"components"` - Observability *ObsConfig `json:"observability,omitempty" yaml:"observability,omitempty"` - Storage *StorageConfig `json:"storage,omitempty" yaml:"storage,omitempty"` - Hosts []*host.Host `json:"hosts" yaml:"hosts"` - SetupState *setup.SetupState `json:"setup_state" yaml:"setup_state"` + Network *NetworkConfig `json:"network,omitempty" yaml:"network,omitempty"` + DNS *DNSConfig `json:"dns,omitempty" yaml:"dns,omitempty"` + Cluster ClusterConfig `json:"cluster" yaml:"cluster"` + Components ComponentMap `json:"components" yaml:"components"` + Observability *ObsConfig `json:"observability,omitempty" yaml:"observability,omitempty"` + Storage *StorageConfig `json:"storage,omitempty" yaml:"storage,omitempty"` + Hosts []*host.Host `json:"hosts" yaml:"hosts"` + SetupState *setup.SetupState `json:"setup_state" yaml:"setup_state"` } -