Add --bind-conf flag for BIND domains.conf generation
Generate a BIND-format domains.conf file alongside catalog zones. New input properties: file= (zone data path) and dnssec (bare flag). When --bind-conf is set, every zone must have file= or it errors. Renames ZoneEntry.File to ZonesFile (input path for error messages) and adds ZoneFile (BIND file path) and DNSSEC (bool) fields.
This commit is contained in:
125
main_test.go
125
main_test.go
@@ -38,7 +38,7 @@ app.example.org catalog1, group=external, coo=migrated.example.com.
|
||||
t.Fatalf("loadConfig: %v", err)
|
||||
}
|
||||
|
||||
members, err := parseInput(filepath.Join(dir, "zones.txt"), cfg)
|
||||
_, members, err := parseInput(filepath.Join(dir, "zones.txt"), cfg)
|
||||
if err != nil {
|
||||
t.Fatalf("parseInput: %v", err)
|
||||
}
|
||||
@@ -120,7 +120,7 @@ soa:
|
||||
}
|
||||
|
||||
members1 := []ZoneEntry{
|
||||
{Zone: "a.example.com.", Catalogs: []string{"cat1"}, File: "test", Line: 1},
|
||||
{Zone: "a.example.com.", Catalogs: []string{"cat1"}, ZonesFile: "test", Line: 1},
|
||||
}
|
||||
|
||||
now := fixedTime(2026, 1, 15)
|
||||
@@ -139,8 +139,8 @@ soa:
|
||||
|
||||
// Second run with different input (same day)
|
||||
members2 := []ZoneEntry{
|
||||
{Zone: "a.example.com.", Catalogs: []string{"cat1"}, File: "test", Line: 1},
|
||||
{Zone: "b.example.com.", Catalogs: []string{"cat1"}, File: "test", Line: 2},
|
||||
{Zone: "a.example.com.", Catalogs: []string{"cat1"}, ZonesFile: "test", Line: 1},
|
||||
{Zone: "b.example.com.", Catalogs: []string{"cat1"}, ZonesFile: "test", Line: 2},
|
||||
}
|
||||
|
||||
changed, err = processCatalog("cat1", cfg, members2, dir, now)
|
||||
@@ -195,9 +195,9 @@ soa:
|
||||
|
||||
// Input in reverse order
|
||||
members := []ZoneEntry{
|
||||
{Zone: "z.example.com.", Catalogs: []string{"cat1"}, File: "test", Line: 1},
|
||||
{Zone: "m.example.com.", Catalogs: []string{"cat1"}, File: "test", Line: 2},
|
||||
{Zone: "a.example.com.", Catalogs: []string{"cat1"}, File: "test", Line: 3},
|
||||
{Zone: "z.example.com.", Catalogs: []string{"cat1"}, ZonesFile: "test", Line: 1},
|
||||
{Zone: "m.example.com.", Catalogs: []string{"cat1"}, ZonesFile: "test", Line: 2},
|
||||
{Zone: "a.example.com.", Catalogs: []string{"cat1"}, ZonesFile: "test", Line: 3},
|
||||
}
|
||||
|
||||
now := fixedTime(2026, 1, 15)
|
||||
@@ -371,7 +371,7 @@ soa:
|
||||
}
|
||||
|
||||
members := []ZoneEntry{
|
||||
{Zone: "a.example.com.", Catalogs: []string{"cat1"}, File: "test", Line: 1},
|
||||
{Zone: "a.example.com.", Catalogs: []string{"cat1"}, ZonesFile: "test", Line: 1},
|
||||
}
|
||||
|
||||
day1 := fixedTime(2026, 1, 15)
|
||||
@@ -385,8 +385,8 @@ soa:
|
||||
|
||||
// Add a zone on day 2
|
||||
members2 := []ZoneEntry{
|
||||
{Zone: "a.example.com.", Catalogs: []string{"cat1"}, File: "test", Line: 1},
|
||||
{Zone: "b.example.com.", Catalogs: []string{"cat1"}, File: "test", Line: 2},
|
||||
{Zone: "a.example.com.", Catalogs: []string{"cat1"}, ZonesFile: "test", Line: 1},
|
||||
{Zone: "b.example.com.", Catalogs: []string{"cat1"}, ZonesFile: "test", Line: 2},
|
||||
}
|
||||
|
||||
day2 := fixedTime(2026, 1, 16)
|
||||
@@ -404,9 +404,9 @@ soa:
|
||||
// Simulate not using the tool for a while, running on a much later date
|
||||
day3 := fixedTime(2026, 6, 15)
|
||||
members3 := []ZoneEntry{
|
||||
{Zone: "a.example.com.", Catalogs: []string{"cat1"}, File: "test", Line: 1},
|
||||
{Zone: "b.example.com.", Catalogs: []string{"cat1"}, File: "test", Line: 2},
|
||||
{Zone: "c.example.com.", Catalogs: []string{"cat1"}, File: "test", Line: 3},
|
||||
{Zone: "a.example.com.", Catalogs: []string{"cat1"}, ZonesFile: "test", Line: 1},
|
||||
{Zone: "b.example.com.", Catalogs: []string{"cat1"}, ZonesFile: "test", Line: 2},
|
||||
{Zone: "c.example.com.", Catalogs: []string{"cat1"}, ZonesFile: "test", Line: 3},
|
||||
}
|
||||
|
||||
changed, err = processCatalog("cat1", cfg, members3, dir, day3)
|
||||
@@ -420,3 +420,102 @@ soa:
|
||||
content3 := readTestFile(t, filepath.Join(dir, "cat1.example.com.zone"))
|
||||
assertContains(t, content3, "2026061501")
|
||||
}
|
||||
|
||||
func TestIntegrationCLIBindConf(t *testing.T) {
|
||||
binary := filepath.Join(t.TempDir(), "catalog-zone-gen")
|
||||
cmd := exec.Command("go", "build", "-o", binary, ".")
|
||||
cmd.Dir = projectDir(t)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Fatalf("go build failed: %v\n%s", err, out)
|
||||
}
|
||||
|
||||
dir := t.TempDir()
|
||||
|
||||
configContent := `catalogs:
|
||||
catalog1:
|
||||
zone: catalog1.example.com.
|
||||
|
||||
soa:
|
||||
mname: ns1.example.com.
|
||||
rname: hostmaster.example.com.
|
||||
`
|
||||
writeTestFile(t, dir, "catz.yaml", configContent)
|
||||
|
||||
inputContent := `zone.example.org catalog1, file=data/zones/example.org, dnssec
|
||||
zone.example.com catalog1, file=data/zones/example.com
|
||||
`
|
||||
writeTestFile(t, dir, "zones.txt", inputContent)
|
||||
|
||||
bindConfPath := filepath.Join(dir, "domains.conf")
|
||||
|
||||
cmd = exec.Command(binary,
|
||||
"--config", filepath.Join(dir, "catz.yaml"),
|
||||
"--output-dir", dir,
|
||||
"--bind-conf", bindConfPath,
|
||||
filepath.Join(dir, "zones.txt"))
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("catalog-zone-gen failed: %v\n%s", err, out)
|
||||
}
|
||||
|
||||
// Verify bind conf was written
|
||||
content := readTestFile(t, bindConfPath)
|
||||
assertContains(t, content, "# THIS FILE IS GENERATED BY catalog-zone-gen")
|
||||
|
||||
// zone.example.com should come before zone.example.org (sorted)
|
||||
comIdx := strings.Index(content, "zone.example.com")
|
||||
orgIdx := strings.Index(content, "zone.example.org")
|
||||
if comIdx >= orgIdx {
|
||||
t.Error("expected zone.example.com before zone.example.org (alphabetical)")
|
||||
}
|
||||
|
||||
// DNSSEC zone
|
||||
assertContains(t, content, "dnssec-policy standard; inline-signing yes;")
|
||||
// Non-DNSSEC zone should not have it
|
||||
lines := splitLines(content)
|
||||
for _, line := range lines {
|
||||
if strings.Contains(line, "example.com") && strings.Contains(line, "file") {
|
||||
if strings.Contains(line, "dnssec-policy") {
|
||||
t.Error("example.com should not have dnssec-policy")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntegrationCLIBindConfMissingFile(t *testing.T) {
|
||||
binary := filepath.Join(t.TempDir(), "catalog-zone-gen")
|
||||
cmd := exec.Command("go", "build", "-o", binary, ".")
|
||||
cmd.Dir = projectDir(t)
|
||||
if out, err := cmd.CombinedOutput(); err != nil {
|
||||
t.Fatalf("go build failed: %v\n%s", err, out)
|
||||
}
|
||||
|
||||
dir := t.TempDir()
|
||||
|
||||
configContent := `catalogs:
|
||||
catalog1:
|
||||
zone: catalog1.example.com.
|
||||
|
||||
soa:
|
||||
mname: ns1.example.com.
|
||||
rname: hostmaster.example.com.
|
||||
`
|
||||
writeTestFile(t, dir, "catz.yaml", configContent)
|
||||
|
||||
// Zone without file= property
|
||||
inputContent := "zone.example.org catalog1\n"
|
||||
writeTestFile(t, dir, "zones.txt", inputContent)
|
||||
|
||||
bindConfPath := filepath.Join(dir, "domains.conf")
|
||||
|
||||
cmd = exec.Command(binary,
|
||||
"--config", filepath.Join(dir, "catz.yaml"),
|
||||
"--output-dir", dir,
|
||||
"--bind-conf", bindConfPath,
|
||||
filepath.Join(dir, "zones.txt"))
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err == nil {
|
||||
t.Fatal("expected error when file= is missing with --bind-conf")
|
||||
}
|
||||
assertContains(t, string(out), "missing file=")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user