feat(tmpl): {{domain_name}} placeholder — materialize on diff/apply, parameterize on snapshot
Adds internal/tmpl with Materialize (template placeholder -> zone name) and Parameterize (zone name -> placeholder, the inverse used by the template-from-zone snapshot). service.resolve now materializes the template against DomainRef.ZoneName before diffing, so one template can be reused across domains. LoadDomainFull (source query + hand-edited sqlc output, since sqlc is not installed) now also selects zone_name to populate it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BwxdSt4reTm7Dj1oxRvpP3
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
// Package tmpl renders reusable DNS templates for a concrete zone.
|
||||
//
|
||||
// A template stores records containing the {{domain_name}} placeholder; it is
|
||||
// materialised (placeholder -> zone name, without the trailing dot) just
|
||||
// before diff/apply against a specific domain, and parameterised (zone name
|
||||
// -> placeholder) when snapshotting a live zone into a reusable template.
|
||||
package tmpl
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/vasyakrg/dns-autoresolver/internal/model"
|
||||
"github.com/vasyakrg/dns-autoresolver/internal/store/dto"
|
||||
)
|
||||
|
||||
const Placeholder = "{{domain_name}}"
|
||||
|
||||
func zoneName(z string) string { return strings.TrimSuffix(z, ".") }
|
||||
|
||||
// Materialize renders a template's records for the given zone, substituting
|
||||
// {{domain_name}} with the zone name (without the trailing dot) in each
|
||||
// record's Name and every Value.
|
||||
func Materialize(doc dto.TemplateDoc, zone string) []model.Record {
|
||||
z := zoneName(zone)
|
||||
out := make([]model.Record, 0, len(doc.Records))
|
||||
for _, r := range doc.Records {
|
||||
vals := make([]string, len(r.Values))
|
||||
for i, v := range r.Values {
|
||||
vals[i] = strings.ReplaceAll(v, Placeholder, z)
|
||||
}
|
||||
out = append(out, model.Record{
|
||||
Type: model.RecordType(r.Type),
|
||||
Name: strings.ReplaceAll(r.Name, Placeholder, z),
|
||||
TTL: r.TTL,
|
||||
Values: vals,
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// Parameterize replaces occurrences of the zone name with {{domain_name}} in
|
||||
// record names and values, so a snapshot of a live zone becomes portable.
|
||||
// Records with no zone-name occurrence (DKIM key, external CNAME target) are
|
||||
// left unchanged.
|
||||
func Parameterize(recs []model.Record, zone string) dto.TemplateDoc {
|
||||
z := zoneName(zone)
|
||||
out := dto.TemplateDoc{Records: make([]dto.RecordDTO, 0, len(recs))}
|
||||
for _, r := range recs {
|
||||
vals := make([]string, len(r.Values))
|
||||
for i, v := range r.Values {
|
||||
vals[i] = strings.ReplaceAll(v, z, Placeholder)
|
||||
}
|
||||
out.Records = append(out.Records, dto.RecordDTO{
|
||||
Type: string(r.Type),
|
||||
Name: strings.ReplaceAll(r.Name, z, Placeholder),
|
||||
TTL: r.TTL,
|
||||
Values: vals,
|
||||
})
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user