Replace InstanceConfig with DNSEntry for dnsmasq config generation

InstanceConfig was a ~50-field struct designed for Wild Cloud k8s instances,
but only 3 fields were ever read by dnsmasq (the sole consumer). The
reconciliation bridge constructed fake InstanceConfig objects from registered
domains just to satisfy this interface.

Replace with DNSEntry{Domain, IP} — a 2-field struct purpose-built for
dnsmasq. All domains get local=/ directives to prevent AAAA queries from
leaking to upstream DNS (Happy Eyeballs / RFC 8305 latency on LAN).

Removed dead code: InstanceConfig, NodeConfig, LoadCloudConfig,
SaveCloudConfig, DeepMerge, LoadMergedInstanceConfig, EnsureInstanceConfig,
instance path helpers, instanceLoadBalancerIP, GenerateInstanceConfig,
and all modular per-instance dnsmasq methods.
This commit is contained in:
2026-07-11 20:42:33 +00:00
parent 1f3fcf50b4
commit f9d87ff975
10 changed files with 192 additions and 1517 deletions

View File

@@ -1,7 +1,6 @@
package config
import (
"os"
"path/filepath"
"strings"
"sync"
@@ -18,139 +17,6 @@ func TestNewManager(t *testing.T) {
}
}
// Test: EnsureInstanceConfig creates config file with proper structure
func TestEnsureInstanceConfig(t *testing.T) {
const instanceName = "test-instance"
tests := []struct {
name string
setupFunc func(t *testing.T, dataDir string)
wantErr bool
errContains string
}{
{
name: "creates config when not exists",
setupFunc: nil,
wantErr: false,
},
{
name: "returns nil when config exists",
setupFunc: func(t *testing.T, dataDir string) {
configPath := filepath.Join(dataDir, "instances", instanceName, "config", "instance.yaml")
if err := os.MkdirAll(filepath.Dir(configPath), 0755); err != nil {
t.Fatalf("setup mkdir failed: %v", err)
}
content := `operator:
email: ""
cloud:
baseDomain: "test.local"
domain: "test"
internalDomain: "internal.test"
dhcpRange: ""
dns:
ip: ""
router:
ip: ""
dnsmasq:
interface: ""
nfs:
host: ""
mediaPath: ""
storageCapacity: ""
dockerRegistryHost: ""
cluster:
name: ""
loadBalancerIp: ""
ipAddressPool: ""
hostnamePrefix: ""
certManager:
cloudflare:
domain: ""
externalDns:
ownerId: ""
dockerRegistry:
storage: ""
nodes:
talos:
version: ""
schematicId: ""
control:
vip: ""
active: {}
apps: {}
`
if err := storage.WriteFile(configPath, []byte(content), 0644); err != nil {
t.Fatalf("setup failed: %v", err)
}
},
wantErr: false,
},
{
name: "returns error when config is invalid yaml",
setupFunc: func(t *testing.T, dataDir string) {
configPath := filepath.Join(dataDir, "instances", instanceName, "config", "instance.yaml")
if err := os.MkdirAll(filepath.Dir(configPath), 0755); err != nil {
t.Fatalf("setup mkdir failed: %v", err)
}
if err := storage.WriteFile(configPath, []byte(`invalid: yaml: content: [[[`), 0644); err != nil {
t.Fatalf("setup failed: %v", err)
}
},
wantErr: true,
errContains: "invalid config file",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dataDir := t.TempDir()
m := NewManager()
if tt.setupFunc != nil {
tt.setupFunc(t, dataDir)
}
err := m.EnsureInstanceConfig(instanceName, dataDir)
if tt.wantErr {
if err == nil {
t.Error("expected error, got nil")
} else if tt.errContains != "" && !strings.Contains(err.Error(), tt.errContains) {
t.Errorf("error %q does not contain %q", err.Error(), tt.errContains)
}
return
}
if err != nil {
t.Errorf("unexpected error: %v", err)
return
}
// Verify config file exists
configPath := filepath.Join(dataDir, "instances", instanceName, "config", "instance.yaml")
if !storage.FileExists(configPath) {
t.Error("config file not created")
}
// Verify config is valid YAML
if err := m.ValidateConfig(configPath); err != nil {
t.Errorf("config validation failed: %v", err)
}
// Verify config has expected structure (canonical nested format)
content, err := storage.ReadFile(configPath)
if err != nil {
t.Fatalf("failed to read config: %v", err)
}
contentStr := string(content)
requiredFields := []string{"operator:", "cloud:", "cluster:", "apps:"}
for _, field := range requiredFields {
if !strings.Contains(contentStr, field) {
t.Errorf("config missing required field: %s", field)
}
}
})
}
}
// Test: GetConfigValue retrieves values correctly
func TestGetConfigValue(t *testing.T) {
tests := []struct {
@@ -821,102 +687,3 @@ func TestCopyConfig_Errors(t *testing.T) {
}
}
// Test: File permissions are preserved
func TestEnsureInstanceConfig_FilePermissions(t *testing.T) {
tempDir := t.TempDir()
m := NewManager()
if err := m.EnsureInstanceConfig("my-wild-cloud", tempDir); err != nil {
t.Fatalf("EnsureInstanceConfig failed: %v", err)
}
configPath := filepath.Join(tempDir, "instances", "my-wild-cloud", "config", "instance.yaml")
info, err := os.Stat(configPath)
if err != nil {
t.Fatalf("failed to stat config file: %v", err)
}
// Verify file has 0644 permissions
if info.Mode().Perm() != 0644 {
t.Errorf("expected permissions 0644, got %v", info.Mode().Perm())
}
}
// Test: Idempotent config creation
func TestEnsureInstanceConfig_Idempotent(t *testing.T) {
tempDir := t.TempDir()
m := NewManager()
// First call creates config
if err := m.EnsureInstanceConfig("my-wild-cloud", tempDir); err != nil {
t.Fatalf("first EnsureInstanceConfig failed: %v", err)
}
configPath := filepath.Join(tempDir, "instances", "my-wild-cloud", "config", "instance.yaml")
firstContent, err := storage.ReadFile(configPath)
if err != nil {
t.Fatalf("failed to read config: %v", err)
}
// Second call should not modify config
if err := m.EnsureInstanceConfig("my-wild-cloud", tempDir); err != nil {
t.Fatalf("second EnsureInstanceConfig failed: %v", err)
}
secondContent, err := storage.ReadFile(configPath)
if err != nil {
t.Fatalf("failed to read config: %v", err)
}
if string(firstContent) != string(secondContent) {
t.Error("config content changed on second call")
}
}
// Test: Config structure contains all required fields
func TestEnsureInstanceConfig_RequiredFields(t *testing.T) {
tempDir := t.TempDir()
m := NewManager()
if err := m.EnsureInstanceConfig("my-wild-cloud", tempDir); err != nil {
t.Fatalf("EnsureInstanceConfig failed: %v", err)
}
configPath := filepath.Join(tempDir, "instances", "my-wild-cloud", "config", "instance.yaml")
content, err := storage.ReadFile(configPath)
if err != nil {
t.Fatalf("failed to read config: %v", err)
}
contentStr := string(content)
requiredFields := []string{
"operator:",
"cloud:",
"baseDomain:",
"domain:",
"internalDomain:",
"dhcpRange:",
"nfs:",
"cluster:",
"loadBalancerIp:",
"ipAddressPool:",
"hostnamePrefix:",
"certManager:",
"externalDns:",
"dockerRegistry:",
"nodes:",
"talos:",
"version:",
"schematicId:",
"control:",
"vip:",
"active:",
"apps:",
}
for _, field := range requiredFields {
if !strings.Contains(contentStr, field) {
t.Errorf("config missing required field: %s", field)
}
}
}