Files
catz/config.go
Ask Bjørn Hansen 9ff9abeabd Add also-notify support for BIND domains.conf generation
Extend catz.yaml config with a bind-conf section mapping catalog names
to also-notify IP lists. Zones in catalogs with also-notify configured
get an also-notify directive in the generated domains.conf. IPs are
deduplicated and sorted when a zone belongs to multiple catalogs.
2026-03-28 14:57:37 -07:00

92 lines
2.1 KiB
Go

package main
import (
"fmt"
"os"
"strings"
"gopkg.in/yaml.v3"
)
// CatalogConfig holds the configuration for a single catalog zone.
type CatalogConfig struct {
Zone string `yaml:"zone"`
}
// SOAConfig holds the configurable SOA fields.
type SOAConfig struct {
Mname string `yaml:"mname"`
Rname string `yaml:"rname"`
}
// BindConfConfig holds BIND-specific configuration for domains.conf generation.
type BindConfConfig struct {
AlsoNotify map[string][]string `yaml:"also-notify"`
}
// Config holds the parsed catz.yaml configuration.
type Config struct {
Catalogs map[string]CatalogConfig `yaml:"catalogs"`
SOA SOAConfig `yaml:"soa"`
BindConf BindConfConfig `yaml:"bind-conf"`
}
func loadConfig(path string) (*Config, error) {
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("reading config: %w", err)
}
var cfg Config
if err := yaml.Unmarshal(data, &cfg); err != nil {
return nil, fmt.Errorf("parsing config: %w", err)
}
if err := validateConfig(&cfg); err != nil {
return nil, err
}
// Normalize zone FQDNs
for name, cat := range cfg.Catalogs {
cat.Zone = normalizeFQDN(cat.Zone)
cfg.Catalogs[name] = cat
}
cfg.SOA.Mname = normalizeFQDN(cfg.SOA.Mname)
cfg.SOA.Rname = normalizeFQDN(cfg.SOA.Rname)
return &cfg, nil
}
func validateConfig(cfg *Config) error {
if len(cfg.Catalogs) == 0 {
return fmt.Errorf("config: no catalogs defined")
}
for name, cat := range cfg.Catalogs {
if cat.Zone == "" {
return fmt.Errorf("config: catalog %q has no zone defined", name)
}
}
if cfg.SOA.Mname == "" {
return fmt.Errorf("config: soa.mname is required")
}
if cfg.SOA.Rname == "" {
return fmt.Errorf("config: soa.rname is required")
}
for catName := range cfg.BindConf.AlsoNotify {
if _, ok := cfg.Catalogs[catName]; !ok {
return fmt.Errorf("config: bind-conf.also-notify references unknown catalog %q", catName)
}
}
return nil
}
func normalizeFQDN(name string) string {
name = strings.ToLower(strings.TrimSpace(name))
if name != "" && !strings.HasSuffix(name, ".") {
name += "."
}
return name
}