Add seed migration with zones and records from CoreDNS zone files
Populates the database on first run with the two existing zones (svc.mcp.metacircular.net, mcp.metacircular.net) and all their A records (metacrypt, mcr, sgard, mcp-agent, rift, ns). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -38,6 +38,34 @@ CREATE TABLE IF NOT EXISTS records (
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_records_zone_name ON records(zone_id, name);`,
|
||||
},
|
||||
{
|
||||
Version: 2,
|
||||
Name: "seed zones and records from CoreDNS zone files",
|
||||
SQL: `
|
||||
-- Zone: svc.mcp.metacircular.net (service addresses)
|
||||
INSERT INTO zones (id, name, primary_ns, admin_email, refresh, retry, expire, minimum_ttl, serial)
|
||||
VALUES (1, 'svc.mcp.metacircular.net', 'ns.mcp.metacircular.net.', 'admin.metacircular.net.', 3600, 600, 86400, 300, 2026032601);
|
||||
|
||||
-- Zone: mcp.metacircular.net (node addresses)
|
||||
INSERT INTO zones (id, name, primary_ns, admin_email, refresh, retry, expire, minimum_ttl, serial)
|
||||
VALUES (2, 'mcp.metacircular.net', 'ns.mcp.metacircular.net.', 'admin.metacircular.net.', 3600, 600, 86400, 300, 2026032501);
|
||||
|
||||
-- svc.mcp.metacircular.net records
|
||||
INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'metacrypt', 'A', '192.168.88.181', 300);
|
||||
INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'metacrypt', 'A', '100.95.252.120', 300);
|
||||
INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'mcr', 'A', '192.168.88.181', 300);
|
||||
INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'mcr', 'A', '100.95.252.120', 300);
|
||||
INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'sgard', 'A', '192.168.88.181', 300);
|
||||
INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'sgard', 'A', '100.95.252.120', 300);
|
||||
INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'mcp-agent', 'A', '192.168.88.181', 300);
|
||||
INSERT INTO records (zone_id, name, type, value, ttl) VALUES (1, 'mcp-agent', 'A', '100.95.252.120', 300);
|
||||
|
||||
-- mcp.metacircular.net records
|
||||
INSERT INTO records (zone_id, name, type, value, ttl) VALUES (2, 'rift', 'A', '192.168.88.181', 300);
|
||||
INSERT INTO records (zone_id, name, type, value, ttl) VALUES (2, 'rift', 'A', '100.95.252.120', 300);
|
||||
INSERT INTO records (zone_id, name, type, value, ttl) VALUES (2, 'ns', 'A', '192.168.88.181', 300);
|
||||
INSERT INTO records (zone_id, name, type, value, ttl) VALUES (2, 'ns', 'A', '100.95.252.120', 300);`,
|
||||
},
|
||||
}
|
||||
|
||||
// Migrate applies all pending migrations.
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
|
||||
func createTestZone(t *testing.T, db *DB) *Zone {
|
||||
t.Helper()
|
||||
zone, err := db.CreateZone("svc.mcp.metacircular.net", "ns.mcp.metacircular.net.", "admin.metacircular.net.", 3600, 600, 86400, 300)
|
||||
zone, err := db.CreateZone("test.example.com", "ns.example.com.", "admin.example.com.", 3600, 600, 86400, 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create zone: %v", err)
|
||||
}
|
||||
@@ -18,7 +18,7 @@ func TestCreateRecordA(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
createTestZone(t, db)
|
||||
|
||||
record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
|
||||
record, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create record: %v", err)
|
||||
}
|
||||
@@ -37,7 +37,7 @@ func TestCreateRecordAAAA(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
createTestZone(t, db)
|
||||
|
||||
record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "AAAA", "2001:db8::1", 300)
|
||||
record, err := db.CreateRecord("test.example.com", "metacrypt", "AAAA", "2001:db8::1", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create record: %v", err)
|
||||
}
|
||||
@@ -50,7 +50,7 @@ func TestCreateRecordCNAME(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
createTestZone(t, db)
|
||||
|
||||
record, err := db.CreateRecord("svc.mcp.metacircular.net", "alias", "CNAME", "rift.mcp.metacircular.net.", 300)
|
||||
record, err := db.CreateRecord("test.example.com", "alias", "CNAME", "rift.mcp.metacircular.net.", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create record: %v", err)
|
||||
}
|
||||
@@ -63,7 +63,7 @@ func TestCreateRecordInvalidIP(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
createTestZone(t, db)
|
||||
|
||||
_, err := db.CreateRecord("svc.mcp.metacircular.net", "bad", "A", "not-an-ip", 300)
|
||||
_, err := db.CreateRecord("test.example.com", "bad", "A", "not-an-ip", 300)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for invalid IPv4")
|
||||
}
|
||||
@@ -74,13 +74,13 @@ func TestCreateRecordCNAMEExclusivity(t *testing.T) {
|
||||
createTestZone(t, db)
|
||||
|
||||
// Create an A record first.
|
||||
_, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
|
||||
_, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create A record: %v", err)
|
||||
}
|
||||
|
||||
// Trying to add a CNAME for the same name should fail.
|
||||
_, err = db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "CNAME", "rift.mcp.metacircular.net.", 300)
|
||||
_, err = db.CreateRecord("test.example.com", "metacrypt", "CNAME", "rift.mcp.metacircular.net.", 300)
|
||||
if !errors.Is(err, ErrConflict) {
|
||||
t.Fatalf("expected ErrConflict, got %v", err)
|
||||
}
|
||||
@@ -91,13 +91,13 @@ func TestCreateRecordCNAMEExclusivityReverse(t *testing.T) {
|
||||
createTestZone(t, db)
|
||||
|
||||
// Create a CNAME record first.
|
||||
_, err := db.CreateRecord("svc.mcp.metacircular.net", "alias", "CNAME", "rift.mcp.metacircular.net.", 300)
|
||||
_, err := db.CreateRecord("test.example.com", "alias", "CNAME", "rift.mcp.metacircular.net.", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create CNAME record: %v", err)
|
||||
}
|
||||
|
||||
// Trying to add an A record for the same name should fail.
|
||||
_, err = db.CreateRecord("svc.mcp.metacircular.net", "alias", "A", "192.168.88.181", 300)
|
||||
_, err = db.CreateRecord("test.example.com", "alias", "A", "192.168.88.181", 300)
|
||||
if !errors.Is(err, ErrConflict) {
|
||||
t.Fatalf("expected ErrConflict, got %v", err)
|
||||
}
|
||||
@@ -108,12 +108,12 @@ func TestCreateRecordBumpsSerial(t *testing.T) {
|
||||
zone := createTestZone(t, db)
|
||||
originalSerial := zone.Serial
|
||||
|
||||
_, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
|
||||
_, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create record: %v", err)
|
||||
}
|
||||
|
||||
updated, err := db.GetZone("svc.mcp.metacircular.net")
|
||||
updated, err := db.GetZone("test.example.com")
|
||||
if err != nil {
|
||||
t.Fatalf("get zone: %v", err)
|
||||
}
|
||||
@@ -126,21 +126,21 @@ func TestListRecords(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
createTestZone(t, db)
|
||||
|
||||
_, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
|
||||
_, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create record 1: %v", err)
|
||||
}
|
||||
_, err = db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "100.95.252.120", 300)
|
||||
_, err = db.CreateRecord("test.example.com", "metacrypt", "A", "100.95.252.120", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create record 2: %v", err)
|
||||
}
|
||||
_, err = db.CreateRecord("svc.mcp.metacircular.net", "mcr", "A", "192.168.88.181", 300)
|
||||
_, err = db.CreateRecord("test.example.com", "mcr", "A", "192.168.88.181", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create record 3: %v", err)
|
||||
}
|
||||
|
||||
// List all records.
|
||||
records, err := db.ListRecords("svc.mcp.metacircular.net", "", "")
|
||||
records, err := db.ListRecords("test.example.com", "", "")
|
||||
if err != nil {
|
||||
t.Fatalf("list records: %v", err)
|
||||
}
|
||||
@@ -149,7 +149,7 @@ func TestListRecords(t *testing.T) {
|
||||
}
|
||||
|
||||
// Filter by name.
|
||||
records, err = db.ListRecords("svc.mcp.metacircular.net", "metacrypt", "")
|
||||
records, err = db.ListRecords("test.example.com", "metacrypt", "")
|
||||
if err != nil {
|
||||
t.Fatalf("list records by name: %v", err)
|
||||
}
|
||||
@@ -158,7 +158,7 @@ func TestListRecords(t *testing.T) {
|
||||
}
|
||||
|
||||
// Filter by type.
|
||||
records, err = db.ListRecords("svc.mcp.metacircular.net", "", "A")
|
||||
records, err = db.ListRecords("test.example.com", "", "A")
|
||||
if err != nil {
|
||||
t.Fatalf("list records by type: %v", err)
|
||||
}
|
||||
@@ -171,7 +171,7 @@ func TestUpdateRecord(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
createTestZone(t, db)
|
||||
|
||||
record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
|
||||
record, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create record: %v", err)
|
||||
}
|
||||
@@ -192,7 +192,7 @@ func TestDeleteRecord(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
createTestZone(t, db)
|
||||
|
||||
record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
|
||||
record, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create record: %v", err)
|
||||
}
|
||||
@@ -211,12 +211,12 @@ func TestDeleteRecordBumpsSerial(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
createTestZone(t, db)
|
||||
|
||||
record, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
|
||||
record, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create record: %v", err)
|
||||
}
|
||||
|
||||
zone, err := db.GetZone("svc.mcp.metacircular.net")
|
||||
zone, err := db.GetZone("test.example.com")
|
||||
if err != nil {
|
||||
t.Fatalf("get zone: %v", err)
|
||||
}
|
||||
@@ -226,7 +226,7 @@ func TestDeleteRecordBumpsSerial(t *testing.T) {
|
||||
t.Fatalf("delete record: %v", err)
|
||||
}
|
||||
|
||||
zone, err = db.GetZone("svc.mcp.metacircular.net")
|
||||
zone, err = db.GetZone("test.example.com")
|
||||
if err != nil {
|
||||
t.Fatalf("get zone after delete: %v", err)
|
||||
}
|
||||
@@ -239,12 +239,12 @@ func TestLookupRecords(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
createTestZone(t, db)
|
||||
|
||||
_, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
|
||||
_, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create record: %v", err)
|
||||
}
|
||||
|
||||
records, err := db.LookupRecords("svc.mcp.metacircular.net", "metacrypt", "A")
|
||||
records, err := db.LookupRecords("test.example.com", "metacrypt", "A")
|
||||
if err != nil {
|
||||
t.Fatalf("lookup records: %v", err)
|
||||
}
|
||||
@@ -260,7 +260,7 @@ func TestCreateRecordCNAMEMissingDot(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
createTestZone(t, db)
|
||||
|
||||
_, err := db.CreateRecord("svc.mcp.metacircular.net", "alias", "CNAME", "rift.mcp.metacircular.net", 300)
|
||||
_, err := db.CreateRecord("test.example.com", "alias", "CNAME", "rift.mcp.metacircular.net", 300)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for CNAME without trailing dot")
|
||||
}
|
||||
@@ -270,16 +270,16 @@ func TestMultipleARecords(t *testing.T) {
|
||||
db := openTestDB(t)
|
||||
createTestZone(t, db)
|
||||
|
||||
_, err := db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
|
||||
_, err := db.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create first A record: %v", err)
|
||||
}
|
||||
_, err = db.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "100.95.252.120", 300)
|
||||
_, err = db.CreateRecord("test.example.com", "metacrypt", "A", "100.95.252.120", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create second A record: %v", err)
|
||||
}
|
||||
|
||||
records, err := db.LookupRecords("svc.mcp.metacircular.net", "metacrypt", "A")
|
||||
records, err := db.LookupRecords("test.example.com", "metacrypt", "A")
|
||||
if err != nil {
|
||||
t.Fatalf("lookup records: %v", err)
|
||||
}
|
||||
|
||||
@@ -79,8 +79,9 @@ func TestListZones(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("list zones: %v", err)
|
||||
}
|
||||
if len(zones) != 2 {
|
||||
t.Fatalf("got %d zones, want 2", len(zones))
|
||||
// 2 seed zones + 2 created = 4 total. Verify ours are present and ordered.
|
||||
if len(zones) != 4 {
|
||||
t.Fatalf("got %d zones, want 4", len(zones))
|
||||
}
|
||||
if zones[0].Name != "a.example.com" {
|
||||
t.Fatalf("zones should be ordered by name, got %q first", zones[0].Name)
|
||||
|
||||
@@ -29,23 +29,23 @@ func setupTestServer(t *testing.T) (*Server, *db.DB) {
|
||||
database := openTestDB(t)
|
||||
logger := slog.Default()
|
||||
|
||||
_, err := database.CreateZone("svc.mcp.metacircular.net", "ns.mcp.metacircular.net.", "admin.metacircular.net.", 3600, 600, 86400, 300)
|
||||
_, err := database.CreateZone("test.example.com", "ns.example.com.", "admin.example.com.", 3600, 600, 86400, 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create zone: %v", err)
|
||||
}
|
||||
_, err = database.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "192.168.88.181", 300)
|
||||
_, err = database.CreateRecord("test.example.com", "metacrypt", "A", "192.168.88.181", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create A record: %v", err)
|
||||
}
|
||||
_, err = database.CreateRecord("svc.mcp.metacircular.net", "metacrypt", "A", "100.95.252.120", 300)
|
||||
_, err = database.CreateRecord("test.example.com", "metacrypt", "A", "100.95.252.120", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create A record 2: %v", err)
|
||||
}
|
||||
_, err = database.CreateRecord("svc.mcp.metacircular.net", "mcr", "AAAA", "2001:db8::1", 300)
|
||||
_, err = database.CreateRecord("test.example.com", "mcr", "AAAA", "2001:db8::1", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create AAAA record: %v", err)
|
||||
}
|
||||
_, err = database.CreateRecord("svc.mcp.metacircular.net", "alias", "CNAME", "metacrypt.svc.mcp.metacircular.net.", 300)
|
||||
_, err = database.CreateRecord("test.example.com", "alias", "CNAME", "metacrypt.test.example.com.", 300)
|
||||
if err != nil {
|
||||
t.Fatalf("create CNAME record: %v", err)
|
||||
}
|
||||
@@ -57,12 +57,12 @@ func setupTestServer(t *testing.T) (*Server, *db.DB) {
|
||||
func TestFindZone(t *testing.T) {
|
||||
srv, _ := setupTestServer(t)
|
||||
|
||||
zone := srv.findZone("metacrypt.svc.mcp.metacircular.net.")
|
||||
zone := srv.findZone("metacrypt.test.example.com.")
|
||||
if zone == nil {
|
||||
t.Fatal("expected to find zone")
|
||||
}
|
||||
if zone.Name != "svc.mcp.metacircular.net" {
|
||||
t.Fatalf("got zone %q, want %q", zone.Name, "svc.mcp.metacircular.net")
|
||||
if zone.Name != "test.example.com" {
|
||||
t.Fatalf("got zone %q, want %q", zone.Name, "test.example.com")
|
||||
}
|
||||
|
||||
zone = srv.findZone("nonexistent.com.")
|
||||
@@ -73,17 +73,17 @@ func TestFindZone(t *testing.T) {
|
||||
|
||||
func TestBuildSOA(t *testing.T) {
|
||||
srv, database := setupTestServer(t)
|
||||
zone, err := database.GetZone("svc.mcp.metacircular.net")
|
||||
zone, err := database.GetZone("test.example.com")
|
||||
if err != nil {
|
||||
t.Fatalf("get zone: %v", err)
|
||||
}
|
||||
|
||||
soa := srv.buildSOA(zone)
|
||||
if soa.Ns != "ns.mcp.metacircular.net." {
|
||||
t.Fatalf("got ns %q, want %q", soa.Ns, "ns.mcp.metacircular.net.")
|
||||
if soa.Ns != "ns.example.com." {
|
||||
t.Fatalf("got ns %q, want %q", soa.Ns, "ns.example.com.")
|
||||
}
|
||||
if soa.Hdr.Name != "svc.mcp.metacircular.net." {
|
||||
t.Fatalf("got name %q, want %q", soa.Hdr.Name, "svc.mcp.metacircular.net.")
|
||||
if soa.Hdr.Name != "test.example.com." {
|
||||
t.Fatalf("got name %q, want %q", soa.Hdr.Name, "test.example.com.")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ func TestRecordToRR_A(t *testing.T) {
|
||||
srv, _ := setupTestServer(t)
|
||||
|
||||
rec := db.Record{Name: "metacrypt", Type: "A", Value: "192.168.88.181", TTL: 300}
|
||||
rr := srv.recordToRR("metacrypt.svc.mcp.metacircular.net.", rec)
|
||||
rr := srv.recordToRR("metacrypt.test.example.com.", rec)
|
||||
if rr == nil {
|
||||
t.Fatal("expected non-nil RR")
|
||||
}
|
||||
@@ -109,7 +109,7 @@ func TestRecordToRR_AAAA(t *testing.T) {
|
||||
srv, _ := setupTestServer(t)
|
||||
|
||||
rec := db.Record{Name: "mcr", Type: "AAAA", Value: "2001:db8::1", TTL: 300}
|
||||
rr := srv.recordToRR("mcr.svc.mcp.metacircular.net.", rec)
|
||||
rr := srv.recordToRR("mcr.test.example.com.", rec)
|
||||
if rr == nil {
|
||||
t.Fatal("expected non-nil RR")
|
||||
}
|
||||
@@ -126,8 +126,8 @@ func TestRecordToRR_AAAA(t *testing.T) {
|
||||
func TestRecordToRR_CNAME(t *testing.T) {
|
||||
srv, _ := setupTestServer(t)
|
||||
|
||||
rec := db.Record{Name: "alias", Type: "CNAME", Value: "metacrypt.svc.mcp.metacircular.net.", TTL: 300}
|
||||
rr := srv.recordToRR("alias.svc.mcp.metacircular.net.", rec)
|
||||
rec := db.Record{Name: "alias", Type: "CNAME", Value: "metacrypt.test.example.com.", TTL: 300}
|
||||
rr := srv.recordToRR("alias.test.example.com.", rec)
|
||||
if rr == nil {
|
||||
t.Fatal("expected non-nil RR")
|
||||
}
|
||||
@@ -136,7 +136,7 @@ func TestRecordToRR_CNAME(t *testing.T) {
|
||||
if !ok {
|
||||
t.Fatalf("expected *dns.CNAME, got %T", rr)
|
||||
}
|
||||
if cname.Target != "metacrypt.svc.mcp.metacircular.net." {
|
||||
t.Fatalf("got target %q, want %q", cname.Target, "metacrypt.svc.mcp.metacircular.net.")
|
||||
if cname.Target != "metacrypt.test.example.com." {
|
||||
t.Fatalf("got target %q, want %q", cname.Target, "metacrypt.test.example.com.")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user