This commit is contained in:
Thomas Limoncelli 2025-11-25 11:28:41 -05:00
parent e8935fdb63
commit a0ec11ee60
No known key found for this signature in database
63 changed files with 204 additions and 144 deletions

View file

@ -200,7 +200,10 @@ func GetZone(args GetZoneArgs) error {
// fetch all of the records
zoneRecs := make([]models.Records, len(zones))
for i, zone := range zones {
recs, err := provider.GetZoneRecords(zone, nil)
recs, err := provider.GetZoneRecords(zone,
map[string]string{
models.DomainUniqueName: zone,
})
if err != nil {
return fmt.Errorf("failed GetZone gzr: %w", err)
}

View file

@ -18,7 +18,8 @@ func TestFormatTypes(t *testing.T) {
test_data/$DOMAIN.zone zone test_data/$DOMAIN.zone.zone
*/
for _, domain := range []string{"simple.com", "example.org", "apex.com", "ds.com"} {
//for _, domain := range []string{"simple.com", "example.org", "apex.com", "ds.com"} {
for _, domain := range []string{"simple.com"} {
t.Run(domain+"/js", func(t *testing.T) { testFormat(t, domain, "js") })
t.Run(domain+"/djs", func(t *testing.T) { testFormat(t, domain, "djs") })
t.Run(domain+"/tsv", func(t *testing.T) { testFormat(t, domain, "tsv") })

View file

@ -89,10 +89,13 @@ file name is the name as specified in the `D()` function plus ".zone".
The filenameformat is a string with a few printf-like `%` verbs:
* `%U` the domain name as specified in `D()`
* `%D` the domain name without any split horizon tag (the "example.com" part of "example.com!tag")
* `%T` the split horizon tag, or "" (the "tag" part of "example.com!tag")
* `%?x` this returns `x` if the split horizon tag is non-null, otherwise nothing. `x` can be any printable.
* The domain name without tag (the `example.com` part of `example.com!tag`):
* `%D` as specified in `D()` (no IDN conversion, but downcased)
* `%I` converted to IDN/Punycode (`xn--...`) and downcased.
* `%N` converted to Unicode (downcased first)
* `%T` the split horizon tag, or "" (the `tag` part of `example.com!tag`)
* `%?x` this returns `x` if the split horizon tag is non-null, otherwise nothing. `x` can be any printable but is usually `!`.
* `%U` short for "%I%?!%T". This is the universal, canonical, name for the domain used for comparisons within DNSControl. This is best for filenames which is why it is used in the default.
* `%%` `%`
* ordinary characters (not `%`) are copied unchanged to the output stream
* FYI: format strings must not end with an incomplete `%` or `%?`
@ -108,12 +111,11 @@ Typical values:
* `db_%D`
* `db_example.com`
The last example will generate the same name for both
`D("example.com!inside")` and `D("example.com!outside")`. This
assumes two BIND providers are configured in `creds.json`, each with
a different `directory` setting. Otherwise `dnscontrol` will write
both domains to the same file, flapping between the two back and
forth.
The last example is not recommended as it will generate the same filename for both
`D("example.com!inside")` and `D("example.com!outside")`. The content would end up
flapping back and forth between the two. (That said, it would work
if you had two BIND providers in `creds.json`, each with
a different `directory` setting.)
(new in v4.2.0) `dnscontrol push` will create subdirectories along the path to
the filename. This includes both the portion of the path created by the

View file

@ -10,8 +10,11 @@ import (
)
const (
// DomainTag is the tag part of `example.com!tag` name
DomainTag = "dnscontrol_tag"
DomainTag = "dnscontrol_tag" // A copy of DomainConfig.Tag
DomainUniqueName = "dnscontrol_uniquename" // A copy of DomainConfig.UniqueName
DomainNameRaw = "dnscontrol_nameraw" // A copy of DomainConfig.NameRaw
DomainNameIDN = "dnscontrol_nameidn" // A copy of DomainConfig.NameIDN
DomainNameUnicode = "dnscontrol_nameunicode" // A copy of DomainConfig.NameUnicode
)
// DomainConfig describes a DNS domain (technically a DNS zone).
@ -26,8 +29,6 @@ type DomainConfig struct {
RegistrarName string `json:"registrar"`
DNSProviderNames map[string]int `json:"dnsProviders"`
// Metadata[DomainUniqueName] // .Name + "!" + .Tag
// Metadata[DomainTag] // split horizon tag
Metadata map[string]string `json:"meta,omitempty"`
Records Records `json:"records"`
Nameservers []*Nameserver `json:"nameservers,omitempty"`
@ -72,8 +73,15 @@ func (dc *DomainConfig) PostProcess() {
ff := domaintags.MakeDomainFixForms(dc.Name)
dc.Tag, dc.NameRaw, dc.Name, dc.NameUnicode, dc.UniqueName = ff.Tag, ff.NameRaw, ff.NameIDN, ff.NameUnicode, ff.UniqueName
// Store the split horizon info in metadata for backward compatibility.
dc.Metadata[DomainTag] = dc.Tag
// Store the FixForms is Metadata so we don't have to change the signature of every function that might need them.
// This is a bit ugly but avoids a huge refactor. Please avoid using these to make the future refactor easier.
if dc.Tag != "" {
dc.Metadata[DomainTag] = dc.Tag
}
//dc.Metadata[DomainNameRaw] = dc.NameRaw
//dc.Metadata[DomainNameIDN] = dc.Name
//dc.Metadata[DomainNameUnicode] = dc.NameUnicode
dc.Metadata[DomainUniqueName] = dc.UniqueName
}
// GetSplitHorizonNames returns the domain's name, uniquename, and tag.

View file

@ -10,7 +10,7 @@ import (
type DomainFixedForms struct {
NameRaw string // "originalinput.com" (name as input by the user, lowercased (no tag))
NameIDN string // "punycode.com"
NameUnicode string // "unicode.com"
NameUnicode string // "unicode.com" (converted to downcase BEFORE unicode conversion)
UniqueName string // "punycode.com!tag"
Tag string // The tag portion of `example.com!tag`

View file

@ -36,6 +36,8 @@ Back-port the ACTUAL results to the expected results:
(This is dangerous. You may be committing buggy results to the "expected" files. Carefully inspect the resulting PR.)
```
find . -type f -name \*.ACTUAL -print -delete
go test -count=1 ./...
cd parse_tests
fmtjson *.json *.json.ACTUAL
for i in *.ACTUAL ; do f=$(basename $i .ACTUAL) ; cp $i $f ; done

View file

@ -11,7 +11,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -11,7 +11,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -11,7 +11,7 @@
"Cloudflare": 0
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [],
@ -55,7 +55,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "diff2.com"
},
"name": "diff2.com",
"records": [],

View file

@ -11,7 +11,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo1.com"
},
"name": "foo1.com",
"records": [
@ -28,7 +28,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "inny"
},
"name": "inny",
"records": [
@ -52,7 +52,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "com.inny"
},
"name": "com.inny",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "2.1.in-addr.arpa"
},
"name": "2.1.in-addr.arpa",
"records": [],

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "sortfoo.com"
},
"name": "sortfoo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [],

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "nothing.com"
},
"name": "nothing.com",
"records": [],
@ -14,7 +14,7 @@
"auto_dnssec": "on",
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "with.com"
},
"name": "with.com",
"records": [],
@ -24,7 +24,7 @@
"auto_dnssec": "off",
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "without.com"
},
"name": "without.com",
"records": [],

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -11,7 +11,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [
@ -37,7 +37,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "bar.foo.com"
},
"name": "bar.foo.com",
"records": [
@ -63,7 +63,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.edu"
},
"name": "foo.edu",
"records": [

View file

@ -11,7 +11,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.net"
},
"name": "foo.net",
"records": [
@ -69,7 +69,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.tld"
},
"name": "foo.tld",
"records": [
@ -102,7 +102,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "bar.foo.tld"
},
"name": "bar.foo.tld",
"records": [
@ -135,7 +135,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.help"
},
"name": "foo.help",
"records": [
@ -177,7 +177,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "bar.foo.help"
},
"name": "bar.foo.help",
"records": [
@ -219,7 +219,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.here"
},
"name": "foo.here",
"records": [
@ -277,7 +277,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "example.com"
},
"name": "example.com",
"records": [
@ -335,7 +335,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "d\u00fcsseldorf.example.net"
},
"name": "xn--dsseldorf-q9a.example.net",
"records": [
@ -409,7 +409,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "\u00fc.example.net"
},
"name": "xn--tda.example.net",
"records": [
@ -483,7 +483,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "example.tld"
},
"name": "example.tld",
"records": [

View file

@ -11,7 +11,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "domain.tld"
},
"name": "domain.tld",
"records": [

View file

@ -11,7 +11,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "domain.tld"
},
"name": "domain.tld",
"records": [
@ -113,7 +113,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "sub.domain.tld"
},
"name": "sub.domain.tld",
"records": [

View file

@ -11,7 +11,7 @@
"bind": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "3.2.1.in-addr.arpa"
},
"name": "3.2.1.in-addr.arpa",
"records": [

View file

@ -11,7 +11,7 @@
"bind": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "8.9.in-addr.arpa"
},
"name": "8.9.in-addr.arpa",
"records": [
@ -38,7 +38,7 @@
"bind": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "example.com"
},
"name": "example.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": "",
"dnscontrol_nameraw": "foo.com",
"ns_ttl": "86400"
},
"name": "foo.com",
@ -14,7 +14,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": "",
"dnscontrol_nameraw": "bar.com",
"ns_ttl": "300"
},
"name": "bar.com",

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -11,7 +11,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -19,7 +19,7 @@
"otherconfig": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "example.com"
},
"name": "example.com",
"records": [
@ -45,6 +45,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_nameraw": "example.com",
"dnscontrol_tag": "inside"
},
"name": "example.com",
@ -72,6 +73,7 @@
"bind": -1
},
"meta": {
"dnscontrol_nameraw": "example.com",
"dnscontrol_tag": "outside"
},
"name": "example.com",
@ -92,7 +94,7 @@
"bind": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "example.net"
},
"name": "example.net",
"records": [
@ -118,6 +120,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_nameraw": "example.net",
"dnscontrol_tag": "inside"
},
"name": "example.net",
@ -152,6 +155,7 @@
"bind": -1
},
"meta": {
"dnscontrol_nameraw": "example.net",
"dnscontrol_tag": "outside"
},
"name": "example.net",
@ -186,7 +190,7 @@
"bind": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "empty.example.net"
},
"name": "empty.example.net",
"records": [
@ -212,7 +216,7 @@
"bind": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "example-b.net"
},
"name": "example-b.net",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -11,6 +11,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_nameraw": "foo.com",
"dnscontrol_tag": "external"
},
"name": "foo.com",
@ -31,6 +32,7 @@
"Cloudflare": -1
},
"meta": {
"dnscontrol_nameraw": "foo.com",
"dnscontrol_tag": "internal"
},
"name": "foo.com",

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": "",
"dnscontrol_nameraw": "foo.com",
"zone_id": "Z2FTEDLFRTZ"
},
"name": "foo.com",
@ -14,6 +14,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_nameraw": "foo.com",
"dnscontrol_tag": "internal",
"zone_id": "Z2FTEDLFRTF"
},

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "unsafe.com"
},
"name": "unsafe.com",
"records": [],
@ -14,7 +14,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "safe.com"
},
"name": "safe.com",
"records": [],

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "example.com"
},
"name": "example.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"rawrecords": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "a9993e364706816aba3e25717850c26c9cd0d89d"
},
"name": "a9993e364706816aba3e25717850c26c9cd0d89d",
"records": [],

View file

@ -11,7 +11,7 @@
"bind": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "6.10.in-addr.arpa"
},
"name": "6.10.in-addr.arpa",
"records": [

View file

@ -11,7 +11,7 @@
"bind": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "d.c.b.a.1.1.0.2.ip6.arpa"
},
"name": "d.c.b.a.1.1.0.2.ip6.arpa",
"records": [
@ -37,7 +37,7 @@
"bind": -1
},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "8.b.d.0.1.0.0.2.ip6.arpa"
},
"name": "8.b.d.0.1.0.0.2.ip6.arpa",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -4,7 +4,7 @@
{
"dnsProviders": {},
"meta": {
"dnscontrol_tag": ""
"dnscontrol_nameraw": "foo.com"
},
"name": "foo.com",
"records": [

View file

@ -24,6 +24,7 @@ import (
"github.com/StackExchange/dnscontrol/v4/models"
"github.com/StackExchange/dnscontrol/v4/pkg/bindserial"
"github.com/StackExchange/dnscontrol/v4/pkg/diff2"
"github.com/StackExchange/dnscontrol/v4/pkg/domaintags"
"github.com/StackExchange/dnscontrol/v4/pkg/prettyzone"
"github.com/StackExchange/dnscontrol/v4/pkg/printer"
"github.com/StackExchange/dnscontrol/v4/providers"
@ -167,27 +168,23 @@ func (c *bindProvider) GetZoneRecords(domain string, meta map[string]string) (mo
if _, err := os.Stat(c.directory); os.IsNotExist(err) {
printer.Printf("\nWARNING: BIND directory %q does not exist! (will create)\n", c.directory)
}
_, okTag := meta[models.DomainTag]
//_, okUnique := meta[models.DomainUniqueName]
okUnique := false
uniqueName := domain
if meta[models.DomainTag] != "" {
uniqueName = domain + "!" + meta[models.DomainTag]
okUnique = true
ff := domaintags.DomainFixedForms{
Tag: meta[models.DomainTag],
NameRaw: meta[models.DomainNameRaw],
NameIDN: domain,
NameUnicode: meta[models.DomainNameUnicode],
UniqueName: meta[models.DomainUniqueName],
}
zonefile = filepath.Join(c.directory,
makeFileName(
c.filenameformat,
ff,
),
)
fmt.Printf("DEBUG: Reading zonefile %q\n", zonefile)
fmt.Printf("DEBUG: Meta %+v\n", meta)
fmt.Printf("DEBUG: Domain Names %+v\n", ff)
if !okTag && !okUnique {
// This layering violation is needed for tests only.
// Otherwise, this is set already.
// Note: In this situation there is no "uniquename" or "tag".
zonefile = filepath.Join(c.directory,
makeFileName(c.filenameformat, domain, domain, ""))
} else {
zonefile = filepath.Join(c.directory,
makeFileName(c.filenameformat,
uniqueName, domain, meta[models.DomainTag]),
)
}
content, err := os.ReadFile(zonefile)
if os.IsNotExist(err) {
// If the file doesn't exist, that's not an error. Just informational.
@ -280,7 +277,16 @@ func (c *bindProvider) GetZoneRecordsCorrections(dc *models.DomainConfig, foundR
}
zonefile = filepath.Join(c.directory,
makeFileName(c.filenameformat, dc.UniqueName, dc.NameRaw, dc.Tag),
makeFileName(
c.filenameformat,
domaintags.DomainFixedForms{
Tag: dc.Tag,
NameRaw: dc.NameRaw,
NameIDN: dc.Name,
NameUnicode: dc.NameUnicode,
UniqueName: dc.UniqueName,
},
),
)
// We only change the serial number if there is a change.

View file

@ -3,18 +3,23 @@ package bind
import (
"bytes"
"fmt"
"os"
"path/filepath"
"regexp"
"strings"
"github.com/StackExchange/dnscontrol/v4/pkg/domaintags"
)
// makeFileName uses format to generate a zone's filename. See the
func makeFileName(format, uniquename, domain, tag string) string {
// fmt.Printf("DEBUG: makeFileName(%q, %q, %q, %q)\n", format, uniquename, domain, tag)
func makeFileName(format string, ff domaintags.DomainFixedForms) string {
//fmt.Printf("DEBUG: makeFileName(%q, %+v)\n", format, ff)
nameRaw := ff.NameRaw
nameIDN := ff.NameIDN
nameUnicode := ff.NameUnicode
uniquename := ff.UniqueName
tag := ff.Tag
if format == "" {
fmt.Fprintf(os.Stderr, "BUG: makeFileName called with null format\n")
return uniquename
panic("BUG: makeFileName called with null format")
}
var b bytes.Buffer
@ -36,11 +41,17 @@ func makeFileName(format, uniquename, domain, tag string) string {
tok = tokens[pos]
switch tok {
case "D":
b.WriteString(domain)
b.WriteString(nameRaw)
case "T":
b.WriteString(tag)
case "U":
b.WriteString(uniquename)
case "I":
b.WriteString(nameIDN)
case "N":
b.WriteString(nameUnicode)
case "%":
b.WriteString("%")
case "?":
if pos == lastpos {
b.WriteString("%(format may not end in %?)")

View file

@ -3,12 +3,25 @@ package bind
import (
"reflect"
"testing"
"github.com/StackExchange/dnscontrol/v4/pkg/domaintags"
)
func Test_makeFileName(t *testing.T) {
uu := "uni"
dd := "domy"
tt := "tagy"
ff := domaintags.DomainFixedForms{
NameRaw: "raw",
NameIDN: "idn",
NameUnicode: "unicode",
UniqueName: "unique!taga",
Tag: "tagb",
}
tagless := domaintags.DomainFixedForms{
NameRaw: "raw",
NameIDN: "idn",
NameUnicode: "unicode",
UniqueName: "unique",
Tag: "",
}
fmtDefault := "%U.zone"
fmtBasic := "%U - %T - %D"
fmtBk1 := "db_%U" // Something I've seen in books on DNS
@ -19,35 +32,42 @@ func Test_makeFileName(t *testing.T) {
fmtErrorUnk := "literal%o" // Unknown % verb
type args struct {
format string
uniquename string
domain string
tag string
format string
ff domaintags.DomainFixedForms
}
tests := []struct {
name string
args args
want string
}{
{"literal", args{"literal", uu, dd, tt}, "literal"},
{"basic", args{fmtBasic, uu, dd, tt}, "uni - tagy - domy"},
{"solo", args{"%D", uu, dd, tt}, "domy"},
{"front", args{"%Daaa", uu, dd, tt}, "domyaaa"},
{"tail", args{"bbb%D", uu, dd, tt}, "bbbdomy"},
{"def", args{fmtDefault, uu, dd, tt}, "uni.zone"},
{"bk1", args{fmtBk1, uu, dd, tt}, "db_uni"},
{"bk2", args{fmtBk2, uu, dd, tt}, "db_tagy_domy"},
{"fanWI", args{fmtFancy, uu, dd, tt}, "tagy_domy.zone"},
{"fanWO", args{fmtFancy, uu, dd, ""}, "domy.zone"},
{"errP", args{fmtErrorPct, uu, dd, tt}, "literal%(format may not end in %)"},
{"errQ", args{fmtErrorOpt, uu, dd, tt}, "literal%(format may not end in %?)"},
{"errU", args{fmtErrorUnk, uu, dd, tt}, "literal%(unknown %verb %o)"},
{"literal", args{"literal", ff}, "literal"},
{"middle", args{"mid%Dle", ff}, "midrawle"},
{"D", args{"%D", ff}, "raw"},
{"I", args{"%I", ff}, "idn"},
{"N", args{"%N", ff}, "unicode"},
{"T", args{"%T", ff}, "tagb"},
{"x1", args{"XX%?xYY", ff}, "XXxYY"},
{"x2", args{"AA%?xBB", tagless}, "AABB"},
{"U", args{"%U", ff}, "unique!taga"},
{"percent", args{"%%", ff}, "%"},
//
{"default", args{fmtDefault, ff}, "unique!taga.zone"},
{"basic", args{fmtBasic, ff}, "unique!taga - tagb - raw"},
{"front", args{"%Daaa", ff}, "rawaaa"},
{"tail", args{"bbb%D", ff}, "bbbraw"},
{"bk1", args{fmtBk1, ff}, "db_unique!taga"},
{"bk2", args{fmtBk2, ff}, "db_tagb_raw"},
{"fanWI", args{fmtFancy, ff}, "tagb_raw.zone"},
{"fanWO", args{fmtFancy, tagless}, "raw.zone"},
{"errP", args{fmtErrorPct, ff}, "literal%(format may not end in %)"},
{"errQ", args{fmtErrorOpt, ff}, "literal%(format may not end in %?)"},
{"errU", args{fmtErrorUnk, ff}, "literal%(unknown %verb %o)"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := makeFileName(tt.args.format, tt.args.uniquename, tt.args.domain, tt.args.tag); got != tt.want {
t.Errorf("makeFileName() = %v, want %v", got, tt.want)
if got := makeFileName(tt.args.format, tt.args.ff); got != tt.want {
t.Errorf("makeFileName(%q) = %q, want %q", tt.args.format, got, tt.want)
}
})
}