package config import ( "encoding/json" "errors" "fmt" "net/netip" "os" ) type HealthchecksConfig struct { Enabled bool `json:"enabled"` HostPingAPI string `json:"host_ping_api"` PingKey string `json:"ping_key"` } type DNSMasqConfig struct { DHCPRangeStart netip.Addr DHCPRangeEnd netip.Addr LeasesPath string } type NetboxConfig struct { Host string `json:"host"` APIKey string `json:"api_key"` VRFName string `json:"vrf"` } type Config struct { HealthchecksConfig `json:"healthchecks"` DNSMasqConfigFile string `json:"dnsmasq_config"` DNSMasqConfig NetboxConfig `json:"netbox"` } func (c *Config) parseDNSMasqConf() error { dnsMasqRootContent, err := os.ReadFile(c.DNSMasqConfigFile) if err != nil { return fmt.Errorf("failed to read dnsmasq config: %w", err) } dnsmasqRawConf, err := parseDNSMasqOptions(string(dnsMasqRootContent)) if err != nil { return fmt.Errorf("failed to parse dnsmasq config: %w", err) } c.LeasesPath = dnsmasqRawConf.leaseFile c.DHCPRangeStart, err = netip.ParseAddr(dnsmasqRawConf.rangeStart) if err != nil { return fmt.Errorf("failed to parse dhcp range start: %w", err) } c.DHCPRangeEnd, err = netip.ParseAddr(dnsmasqRawConf.rangeEnd) if err != nil { return fmt.Errorf("failed to parse dhcp range end: %w", err) } return nil } func defaultConfig() *Config { return &Config{ HealthchecksConfig: HealthchecksConfig{ Enabled: false, }, DNSMasqConfigFile: "etc/dnsmasq.conf", } } func New(path string) (*Config, error) { fileContent, err := os.ReadFile(path) if err != nil { if errors.Is(err, os.ErrNotExist) { conf := defaultConfig() return conf, conf.parseDNSMasqConf() } return nil, fmt.Errorf("failed to read config file %w", err) } var c Config if err := json.Unmarshal(fileContent, &c); err != nil { return nil, fmt.Errorf("failed to parse config file: %w", err) } return &c, c.parseDNSMasqConf() }