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.
92 lines
2.1 KiB
Go
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
|
|
}
|