Initial bind-operator: 9 CRDs + controllers
Implements a Kubernetes operator that manages fleets of BIND9 servers declaratively, using controller-runtime (matching forgebot conventions). - add BindCluster reconciler: StatefulSet (pod-0 primary, secondaries), headless + client Services, rendered named.conf ConfigMap, TSIG keys Secret and rndc control Secret; watches dependent CRs to re-render - add BindTSIGKey reconciler that generates key material into a Secret - add BindZone/DNSRecord reconcilers using fully-dynamic delivery (rndc addzone + TSIG nsupdate against the primary pod) - add BindCatalogZone reconciler so secondaries auto-provision zones - add BindPolicy (RPZ), BindDNSSECPolicy, BindView, BindACL reconcilers - render primary/secondary named.conf variants selected by pod ordinal - generate CRDs, deepcopy and RBAC; add samples mapping the three Puppet roles (authoritative/resolver/external-dns) to three BindClusters - add Makefile, Dockerfile.operator, Woodpecker CI and kind manifests
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
package controller
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
bindv1alpha1 "git.unkin.net/unkin/bind-operator/api/v1alpha1"
|
||||
)
|
||||
|
||||
func TestFQDN(t *testing.T) {
|
||||
cases := []struct{ name, zone, want string }{
|
||||
{"@", "example.com", "example.com."},
|
||||
{"", "example.com", "example.com."},
|
||||
{"www", "example.com", "www.example.com."},
|
||||
{"www.example.com.", "example.com", "www.example.com."},
|
||||
{"host", "10.in-addr.arpa", "host.10.in-addr.arpa."},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := fqdn(c.name, c.zone); got != c.want {
|
||||
t.Errorf("fqdn(%q,%q)=%q want %q", c.name, c.zone, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRecordsToUpdatesTTLFallback(t *testing.T) {
|
||||
custom := int32(60)
|
||||
records := []bindv1alpha1.Record{
|
||||
{Name: "@", Type: "A", Values: []string{"192.0.2.1"}},
|
||||
{Name: "low", Type: "A", TTL: &custom, Values: []string{"192.0.2.2"}},
|
||||
}
|
||||
updates := recordsToUpdates("example.com", records, 3600)
|
||||
if len(updates) != 2 {
|
||||
t.Fatalf("expected 2 updates, got %d", len(updates))
|
||||
}
|
||||
if updates[0].TTL != 3600 {
|
||||
t.Errorf("expected default TTL 3600, got %d", updates[0].TTL)
|
||||
}
|
||||
if updates[1].TTL != 60 {
|
||||
t.Errorf("expected record TTL 60, got %d", updates[1].TTL)
|
||||
}
|
||||
if updates[0].FQDN != "example.com." {
|
||||
t.Errorf("apex FQDN wrong: %s", updates[0].FQDN)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRPZRulesToUpdates(t *testing.T) {
|
||||
rules := []bindv1alpha1.RPZRule{
|
||||
{Trigger: "qname", Match: "bad.example.com", Action: "nxdomain"},
|
||||
{Trigger: "qname", Match: "walled.example.com", Action: "cname", Target: "block.internal"},
|
||||
}
|
||||
updates := rpzRulesToUpdates("rpz.internal", rules)
|
||||
if len(updates) != 2 {
|
||||
t.Fatalf("expected 2 updates, got %d", len(updates))
|
||||
}
|
||||
if updates[0].FQDN != "bad.example.com.rpz.internal." {
|
||||
t.Errorf("qname owner wrong: %s", updates[0].FQDN)
|
||||
}
|
||||
if updates[0].Values[0] != "." {
|
||||
t.Errorf("nxdomain rdata should be '.', got %q", updates[0].Values[0])
|
||||
}
|
||||
if updates[1].Values[0] != "block.internal." {
|
||||
t.Errorf("cname rdata wrong: %q", updates[1].Values[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestCatalogEnabledDefault(t *testing.T) {
|
||||
on := &bindv1alpha1.BindZone{Spec: bindv1alpha1.BindZoneSpec{Type: bindv1alpha1.ZonePrimary}}
|
||||
if !catalogEnabled(on) {
|
||||
t.Error("primary zone should default to catalog enabled")
|
||||
}
|
||||
no := false
|
||||
off := &bindv1alpha1.BindZone{Spec: bindv1alpha1.BindZoneSpec{Type: bindv1alpha1.ZonePrimary, Catalog: &no}}
|
||||
if catalogEnabled(off) {
|
||||
t.Error("catalog=false should disable membership")
|
||||
}
|
||||
sec := &bindv1alpha1.BindZone{Spec: bindv1alpha1.BindZoneSpec{Type: bindv1alpha1.ZoneSecondary}}
|
||||
if catalogEnabled(sec) {
|
||||
t.Error("secondary zone should never be a catalog member")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user