Standardize codebase consistency: naming, JSON tags, logging, error wrapping

- JSON tags: fix snake_case to camelCase in dnsmasq (configFile, domainsConfigured,
  lastRestart), crowdsec Machine (lastPush, lastHeartbeat), network (primaryIP,
  primaryInterface). cscli raw parsing structs keep snake_case to match CLI output.
- Error wrapping: fix %v to %w in enableAuthelia for proper error chain preservation
- Naming: rename dnsmasq.ConfigGenerator to dnsmasq.Manager (matches all other packages),
  rename ServiceStatus to Status in dnsmasq and haproxy (matches authelia, crowdsec, etc.)
- Logging: standardize all slog calls to use "component" key instead of message prefixes.
  Affects reconcile, dnsfilter, ddns — now consistent with dnsmasq, haproxy, nftables, sse.
This commit is contained in:
2026-07-14 04:38:48 +00:00
parent 428d47f876
commit 3172e56288
13 changed files with 135 additions and 116 deletions

View File

@@ -24,36 +24,36 @@ type DNSEntry struct {
Wildcard bool // true: address=/ (all subdomains); false: host-record= (exact match)
}
// ConfigGenerator handles dnsmasq configuration generation
type ConfigGenerator struct {
// Manager handles dnsmasq configuration generation
type Manager struct {
configPath string
filterConfPath string // path to addn-hosts file for DNS filtering
}
// NewConfigGenerator creates a new dnsmasq config generator
func NewConfigGenerator(configPath string) *ConfigGenerator {
// NewManager creates a new dnsmasq config generator
func NewManager(configPath string) *Manager {
if configPath == "" {
configPath = "/etc/dnsmasq.d/wild-cloud.conf"
}
return &ConfigGenerator{
return &Manager{
configPath: configPath,
}
}
// GetConfigPath returns the dnsmasq config file path
func (g *ConfigGenerator) GetConfigPath() string {
func (g *Manager) GetConfigPath() string {
return g.configPath
}
// SetFilterConfPath sets the path to an additional hosts file for DNS filtering.
// When set, the generated config includes an addn-hosts= directive.
func (g *ConfigGenerator) SetFilterConfPath(path string) {
func (g *Manager) SetFilterConfPath(path string) {
g.filterConfPath = path
}
// Generate creates a dnsmasq configuration from registered domain entries.
// It auto-detects the Wild Central server's IP address for the listen directive.
func (g *ConfigGenerator) Generate(cfg *config.State, entries []DNSEntry) string {
func (g *Manager) Generate(cfg *config.State, entries []DNSEntry) string {
// Use configured dnsmasq IP (bound to eth0), falling back to auto-detect.
// Auto-detect can pick wlan0 if that's the default route, which is wrong
// when dnsmasq is only listening on eth0.
@@ -123,7 +123,7 @@ log-dhcp
// A full restart is required because SIGHUP (reload) does not re-read
// host-record= directives — only address=/ and a few other directives
// are reloaded on SIGHUP.
func (g *ConfigGenerator) RestartService() error {
func (g *Manager) RestartService() error {
cmd := exec.Command("systemctl", "restart", "dnsmasq.service")
output, err := cmd.CombinedOutput()
if err != nil {
@@ -133,18 +133,18 @@ func (g *ConfigGenerator) RestartService() error {
return nil
}
// ServiceStatus represents the status of the dnsmasq service
type ServiceStatus struct {
// Status represents the status of the dnsmasq service
type Status struct {
Status string `json:"status"`
PID int `json:"pid"`
IP string `json:"ip"`
ConfigFile string `json:"config_file"`
DomainsConfigured int `json:"domains_configured"`
LastRestart time.Time `json:"last_restart"`
ConfigFile string `json:"configFile"`
DomainsConfigured int `json:"domainsConfigured"`
LastRestart time.Time `json:"lastRestart"`
}
// GetStatus checks the status of the dnsmasq service
func (g *ConfigGenerator) GetStatus() (*ServiceStatus, error) {
func (g *Manager) GetStatus() (*Status, error) {
// Get the Wild Central IP address
dnsIP, err := network.GetWildCentralIP()
if err != nil {
@@ -152,7 +152,7 @@ func (g *ConfigGenerator) GetStatus() (*ServiceStatus, error) {
dnsIP = ""
}
status := &ServiceStatus{
status := &Status{
ConfigFile: g.configPath,
IP: dnsIP,
}
@@ -205,7 +205,7 @@ func (g *ConfigGenerator) GetStatus() (*ServiceStatus, error) {
}
// ReadConfig reads the current dnsmasq configuration
func (g *ConfigGenerator) ReadConfig() (string, error) {
func (g *Manager) ReadConfig() (string, error) {
data, err := os.ReadFile(g.configPath)
if err != nil {
return "", fmt.Errorf("reading dnsmasq config: %w", err)
@@ -214,7 +214,7 @@ func (g *ConfigGenerator) ReadConfig() (string, error) {
}
// UpdateConfig regenerates and writes the dnsmasq configuration and optionally restarts.
func (g *ConfigGenerator) UpdateConfig(cfg *config.State, entries []DNSEntry, restart bool) error {
func (g *Manager) UpdateConfig(cfg *config.State, entries []DNSEntry, restart bool) error {
// Generate fresh config from scratch
configContent := g.Generate(cfg, entries)
@@ -235,7 +235,7 @@ func (g *ConfigGenerator) UpdateConfig(cfg *config.State, entries []DNSEntry, re
// GenerateMainConfig creates the main dnsmasq configuration with global settings.
// Used by the DnsmasqGenerate handler to preview/apply the base config independently
// of domain-specific DNS entries (which are handled by Generate + UpdateConfig).
func (g *ConfigGenerator) GenerateMainConfig(cfg *config.State) string {
func (g *Manager) GenerateMainConfig(cfg *config.State) string {
dnsIP, err := network.GetWildCentralIP()
if err != nil {
slog.Error("failed to detect Wild Central IP", "component", "dnsmasq", "error", err)
@@ -300,7 +300,7 @@ log-dhcp
}
// ValidateConfig tests a dnsmasq configuration file for syntax errors
func (g *ConfigGenerator) ValidateConfig(configPath string) error {
func (g *Manager) ValidateConfig(configPath string) error {
cmd := exec.Command("dnsmasq", "--test", "-C", configPath)
output, err := cmd.CombinedOutput()
if err != nil {
@@ -314,13 +314,13 @@ func (g *ConfigGenerator) ValidateConfig(configPath string) error {
// ReloadService restarts dnsmasq to apply configuration changes.
// Uses a full restart because SIGHUP does not re-read host-record= directives.
func (g *ConfigGenerator) ReloadService() error {
func (g *Manager) ReloadService() error {
return g.RestartService()
}
// ConfigureSystemDNS configures systemd-resolved to use the local dnsmasq server
// This should only be called on first start of dnsmasq
func (g *ConfigGenerator) ConfigureSystemDNS() error {
func (g *Manager) ConfigureSystemDNS() error {
// Auto-detect network info to get the DNS IP
netInfo, err := network.DetectNetworkInfo()
if err != nil {

View File

@@ -18,7 +18,7 @@ func wildcardEntry(domain, ip string) DNSEntry {
// Test: Generate with exact-match entries produces host-record= directives
func TestGenerate_WithEntries(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
entries := []DNSEntry{
entry("cloud.example.com", "192.168.1.10"),
entry("internal.example.com", "192.168.1.10"),
@@ -39,7 +39,7 @@ func TestGenerate_WithEntries(t *testing.T) {
// Test: Generate with no entries still produces valid config skeleton
func TestGenerate_NoEntries(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
out := g.Generate(nil, []DNSEntry{})
@@ -56,7 +56,7 @@ func TestGenerate_NoEntries(t *testing.T) {
// Test: Generate skips entries with empty IP
func TestGenerate_EntryWithoutIP(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
out := g.Generate(nil, []DNSEntry{entry("cloud.example.com", "")})
@@ -67,7 +67,7 @@ func TestGenerate_EntryWithoutIP(t *testing.T) {
// Test: GenerateMainConfig produces valid base config
func TestGenerateMainConfig(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
out := g.GenerateMainConfig(nil)
@@ -81,7 +81,7 @@ func TestGenerateMainConfig(t *testing.T) {
// Test: GenerateMainConfig with DHCP disabled does not include dhcp-range
func TestGenerateMainConfig_DHCPDisabled(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
cfg := &config.State{}
cfg.Cloud.Dnsmasq.DHCP.Enabled = false
@@ -94,7 +94,7 @@ func TestGenerateMainConfig_DHCPDisabled(t *testing.T) {
// Test: GenerateMainConfig with DHCP enabled includes dhcp-range
func TestGenerateMainConfig_DHCPEnabled(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
cfg := &config.State{}
cfg.Cloud.Dnsmasq.DHCP.Enabled = true
cfg.Cloud.Dnsmasq.DHCP.RangeStart = "192.168.8.100"
@@ -114,7 +114,7 @@ func TestGenerateMainConfig_DHCPEnabled(t *testing.T) {
// Test: DHCP without gateway omits dhcp-option=3
func TestGenerateMainConfig_DHCPNoGateway(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
cfg := &config.State{}
cfg.Cloud.Dnsmasq.DHCP.Enabled = true
cfg.Cloud.Dnsmasq.DHCP.RangeStart = "192.168.8.100"
@@ -129,7 +129,7 @@ func TestGenerateMainConfig_DHCPNoGateway(t *testing.T) {
// Test: DHCP explicit gateway is used
func TestGenerateMainConfig_DHCPExplicitGateway(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
cfg := &config.State{}
cfg.Cloud.Dnsmasq.DHCP.Enabled = true
cfg.Cloud.Dnsmasq.DHCP.RangeStart = "192.168.8.100"
@@ -145,7 +145,7 @@ func TestGenerateMainConfig_DHCPExplicitGateway(t *testing.T) {
// Test: DHCP static leases appear in output
func TestGenerateMainConfig_DHCPStaticLeases(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
cfg := &config.State{}
cfg.Cloud.Dnsmasq.DHCP.Enabled = true
cfg.Cloud.Dnsmasq.DHCP.RangeStart = "192.168.8.100"
@@ -167,7 +167,7 @@ func TestGenerateMainConfig_DHCPStaticLeases(t *testing.T) {
// Test: DHCP lease time defaults to 24h when not specified
func TestGenerateMainConfig_DHCPLeaseTimeDefault(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
cfg := &config.State{}
cfg.Cloud.Dnsmasq.DHCP.Enabled = true
cfg.Cloud.Dnsmasq.DHCP.RangeStart = "192.168.8.100"
@@ -180,17 +180,17 @@ func TestGenerateMainConfig_DHCPLeaseTimeDefault(t *testing.T) {
}
}
// Test: NewConfigGenerator uses provided path
func TestNewConfigGenerator_CustomPath(t *testing.T) {
g := NewConfigGenerator("/custom/path/dnsmasq.conf")
// Test: NewManager uses provided path
func TestNewManager_CustomPath(t *testing.T) {
g := NewManager("/custom/path/dnsmasq.conf")
if g.GetConfigPath() != "/custom/path/dnsmasq.conf" {
t.Errorf("got %q, want /custom/path/dnsmasq.conf", g.GetConfigPath())
}
}
// Test: NewConfigGenerator uses default path when empty
func TestNewConfigGenerator_DefaultPath(t *testing.T) {
g := NewConfigGenerator("")
// Test: NewManager uses default path when empty
func TestNewManager_DefaultPath(t *testing.T) {
g := NewManager("")
if g.GetConfigPath() != "/etc/dnsmasq.d/wild-cloud.conf" {
t.Errorf("got %q, want /etc/dnsmasq.d/wild-cloud.conf", g.GetConfigPath())
}
@@ -198,7 +198,7 @@ func TestNewConfigGenerator_DefaultPath(t *testing.T) {
// Test: Exact-match domain produces host-record=
func TestGenerate_ExactMatchDomain(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
globalCfg := &config.State{}
out := g.Generate(globalCfg, []DNSEntry{entry("my-api.payne.io", "192.168.8.151")})
@@ -216,7 +216,7 @@ func TestGenerate_ExactMatchDomain(t *testing.T) {
// Test: Wildcard domain produces address=/ without local=/
func TestGenerate_WildcardDomain(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
globalCfg := &config.State{}
out := g.Generate(globalCfg, []DNSEntry{wildcardEntry("cloud.payne.io", "192.168.8.240")})
@@ -234,7 +234,7 @@ func TestGenerate_WildcardDomain(t *testing.T) {
// Test: No local=/ directives are ever generated
func TestGenerate_NoLocalDirectives(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
globalCfg := &config.State{}
entries := []DNSEntry{
@@ -251,7 +251,7 @@ func TestGenerate_NoLocalDirectives(t *testing.T) {
// Test: filter-AAAA appears in generated config
func TestGenerate_FilterAAAA(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
out := g.Generate(nil, nil)
@@ -262,7 +262,7 @@ func TestGenerate_FilterAAAA(t *testing.T) {
// Test: Mix of exact and wildcard domains
func TestGenerate_MixedDomains(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
globalCfg := &config.State{}
entries := []DNSEntry{
@@ -289,7 +289,7 @@ func TestGenerate_MixedDomains(t *testing.T) {
// Test: empty entries list produces base config with no DNS entries
func TestGenerate_EmptyEntries(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
globalCfg := &config.State{}
out := g.Generate(globalCfg, []DNSEntry{})
@@ -310,7 +310,7 @@ func TestGenerate_EmptyEntries(t *testing.T) {
// Test: multiple exact-match entries each get their own DNS records
func TestGenerate_MultipleEntries(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
globalCfg := &config.State{}
entries := []DNSEntry{
@@ -329,7 +329,7 @@ func TestGenerate_MultipleEntries(t *testing.T) {
}
func TestGenerate_ConfFile(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
g.SetFilterConfPath("/var/lib/wild-central/dns-filter/hosts.blocked")
out := g.Generate(nil, nil)
@@ -343,7 +343,7 @@ func TestGenerate_ConfFile(t *testing.T) {
}
func TestGenerate_NoConfFileWhenEmpty(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
// addnHostsPath is empty by default
out := g.Generate(nil, nil)
@@ -354,7 +354,7 @@ func TestGenerate_NoConfFileWhenEmpty(t *testing.T) {
}
func TestGenerateMainConfig_ConfFile(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
g.SetFilterConfPath("/tmp/hosts.blocked")
cfg := &config.State{}
@@ -367,7 +367,7 @@ func TestGenerateMainConfig_ConfFile(t *testing.T) {
// Test: nil config doesn't panic, uses auto-detect for IP
func TestGenerate_NilConfig(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
out := g.Generate(nil, []DNSEntry{})
@@ -381,7 +381,7 @@ func TestGenerate_NilConfig(t *testing.T) {
// Test: when cfg.Cloud.Dnsmasq.IP is set, uses that instead of auto-detect
func TestGenerate_ConfiguredDnsmasqIP(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
cfg := &config.State{}
cfg.Cloud.Dnsmasq.IP = "192.168.8.100"
@@ -394,7 +394,7 @@ func TestGenerate_ConfiguredDnsmasqIP(t *testing.T) {
// Test: verify no leaked empty entries appear
func TestGenerate_NoLeakedEmptyEntries(t *testing.T) {
g := NewConfigGenerator("/tmp/test-dnsmasq.conf")
g := NewManager("/tmp/test-dnsmasq.conf")
cfg := &config.State{}
cases := []struct {