Add catalog-zone-gen tool
Generate RFC 9432 DNS catalog zone files from a declarative input file. Parses zone-to-catalog assignments with optional group and coo properties, produces deterministic BIND-format output with automatic SOA serial management and change detection.
This commit is contained in:
78
config.go
Normal file
78
config.go
Normal file
@@ -0,0 +1,78 @@
|
||||
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"`
|
||||
}
|
||||
|
||||
// Config holds the parsed catz.yaml configuration.
|
||||
type Config struct {
|
||||
Catalogs map[string]CatalogConfig `yaml:"catalogs"`
|
||||
SOA SOAConfig `yaml:"soa"`
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func normalizeFQDN(name string) string {
|
||||
name = strings.ToLower(strings.TrimSpace(name))
|
||||
if name != "" && !strings.HasSuffix(name, ".") {
|
||||
name += "."
|
||||
}
|
||||
return name
|
||||
}
|
||||
Reference in New Issue
Block a user