Commit graph

2708 commits

Author SHA1 Message Date
Tom Limoncelli
1377d00a30
CHORE: Update dependencies (#3934) 2025-12-18 10:07:14 -05:00
Tom Limoncelli
dcdc252722
BUGFIX: RecordConfig v2 wasn't processing record meta data (#3932)
# Issue

Record-level metadata wasn't being processed by RecordConfig v2

# Resolution

fix it.
2025-12-18 09:29:59 -05:00
Tom Limoncelli
41efba6f03
CHORE: Fix Raw/ASCII/Unicode order (linting) (#3933)
<!--
## Before submiting a pull request

Please make sure you've run the following commands from the root
directory.

    bin/generate-all.sh

(this runs commands like "go generate", fixes formatting, and so on)

## Release changelog section

Help keep the release changelog clear by pre-naming the proper section
in the GitHub pull request title.

Some examples:
* CICD: Add required GHA permissions for goreleaser
* DOCS: Fixed providers with "contributor support" table
* ROUTE53: Allow R53_ALIAS records to enable target health evaluation

More examples/context can be found in the file .goreleaser.yml under the
'build' > 'changelog' key.
!-->
2025-12-18 07:11:12 -05:00
Tom Limoncelli
f7c145a54c
BUGFIX: Multiple bugs in RP (RecordConfig v2) (#3931)
# Issue

Fixes https://github.com/StackExchange/dnscontrol/issues/3918

New "modern" types like RP had multiple bugs:
* When RP() has an error (for example, wrong # of arguments) no error
was printed.
* DefaultTTL() was ignored.
* FQDNs listed in RP() not properly checked to verify the are part of
the D()/D_EXTEND() domain.
* REFACTOR: Implement "double domain" checking and the skip_fqdn_check
override (instead of in validate.go).
* REFACTOR: Always list "names" as Raw, then ASCII, then Unicode.
* REFACTOR: Generate domain DisplayName once, use many places

# Resolution

Fixed and test-cases added to prevent regressions.
2025-12-18 07:00:38 -05:00
Tom Limoncelli
51bf2e34d0
BUGFIX: BIND Fix get-zones for bind when using %D (#3930)
Fixes https://github.com/StackExchange/dnscontrol/issues/3919

# Issue

"get-zones" doesn't generate proper file names using %D and possibly
others.

# Resolution

Special-case get-zones to populate the name varieties.
2025-12-18 06:43:00 -05:00
Tom Limoncelli
9076f405fd
NEW FEATURE: Make "fmt" more like other formatters (warning: New default for -o) (#3927)
# Issue

The "fmt" command doesn't work like Terraform fmt, gofmt, and others. It
should:

* Default should DTRT: Format the existing dnsconfig.js file in place
* Not output a filename if no changes were made
* Don't modify the file's timestamp if no changes were made
* Accept stdin and stdout

# Resolution

All that.

# Potential breaking change

The default for '-o' is now dnsconfig.js instead of stdout. This may
break shell scripts that redirect stdout instead of using '-o' to
specify an output filename. If you use ">" instead of "-o", please
switch to "-o".
2025-12-18 06:41:05 -05:00
Tom Limoncelli
9bb022c56b
DOCS: Modernize URls in writing-providers.md (#3929)
Incorporate suggestions from
https://github.com/StackExchange/dnscontrol/pull/3916#pullrequestreview-3584649428
(I clicked on merge before I saw the comments)

CC @cafferata
2025-12-16 15:34:35 -05:00
Jeffrey Cafferata
97d8c6686d
DOCS: Added code examples for new notification options (#3928)
Added code examples for the new `notify_on_push` and `notify_on_preview`
notification options from
https://github.com/StackExchange/dnscontrol/pull/3910.
2025-12-16 15:34:20 -05:00
Tom Limoncelli
1431526a5d
DOCS: Document no_ns (#3926)
Fixes https://github.com/StackExchange/dnscontrol/issues/3890

# Issue

`no_ns` is undocumented.

# Resolution

Add it to the nameserver examples page and the `D()` page.

---------

Co-authored-by: Jeffrey Cafferata <jeffrey@jcid.nl>
Co-authored-by: ecraven <craven@gmx.net>
Co-authored-by: Peter <peter@nexoid.at>
2025-12-16 15:31:36 -05:00
ecraven
dc1bc46821
DOCS: POWERDNS: Improve powerdns provider metadata documentation (#3925)
Closes #3921

Co-authored-by: Peter <peter@nexoid.at>
Co-authored-by: Tom Limoncelli <6293917+tlimoncelli@users.noreply.github.com>
2025-12-16 14:57:32 -05:00
ecraven
cba298b6df
Other changes and improvements: Show zone.UniqueName instead of zone.Name in informational output. (#3923)
This shows zone!tag (unless tag is empty) instead of just zone in
informational messages.

Closes #3922.

Co-authored-by: Peter <peter@nexoid.at>
2025-12-16 08:19:05 -05:00
Tom Limoncelli
43d2fa8917
CHORE: Update the link to future video meetings (#3917)
# Issue

GItHub Discussions can only have 1 category. With a separate category
for the meeting announcements, it can't also appear in the
announcements, which is where people look for it. This lead to bad
user-experience.

# Resolution

Use a label instead, and post the announcements to the "Announcements"
category. Update the link to use labels.
2025-12-16 08:12:32 -05:00
Tom Limoncelli
2a8e810f91
DOCS: Fix RP page (#3920)
# Issue

RP's page isn't appearing

# Resolution

Add it to the SUMMARY file.
2025-12-15 14:21:35 -05:00
dependabot[bot]
b559eec28e
Build(deps): Bump actions/upload-artifact from 5.0.0 to 6.0.0 (#3914)
Bumps
[actions/upload-artifact](https://github.com/actions/upload-artifact)
from 5.0.0 to 6.0.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/upload-artifact/releases">actions/upload-artifact's
releases</a>.</em></p>
<blockquote>
<h2>v6.0.0</h2>
<h2>v6 - What's new</h2>
<blockquote>
<p>[!IMPORTANT]
actions/upload-artifact@v6 now runs on Node.js 24 (<code>runs.using:
node24</code>) and requires a minimum Actions Runner version of 2.327.1.
If you are using self-hosted runners, ensure they are updated before
upgrading.</p>
</blockquote>
<h3>Node.js 24</h3>
<p>This release updates the runtime to Node.js 24. v5 had preliminary
support for Node.js 24, however this action was by default still running
on Node.js 20. Now this action by default will run on Node.js 24.</p>
<h2>What's Changed</h2>
<ul>
<li>Upload Artifact Node 24 support by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/719">actions/upload-artifact#719</a></li>
<li>fix: update <code>@​actions/artifact</code> for Node.js 24 punycode
deprecation by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/744">actions/upload-artifact#744</a></li>
<li>prepare release v6.0.0 for Node.js 24 support by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/upload-artifact/pull/745">actions/upload-artifact#745</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/upload-artifact/compare/v5.0.0...v6.0.0">https://github.com/actions/upload-artifact/compare/v5.0.0...v6.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="b7c566a772"><code>b7c566a</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/745">#745</a>
from actions/upload-artifact-v6-release</li>
<li><a
href="e516bc8500"><code>e516bc8</code></a>
docs: correct description of Node.js 24 support in README</li>
<li><a
href="ddc45ed9bc"><code>ddc45ed</code></a>
docs: update README to correct action name for Node.js 24 support</li>
<li><a
href="615b319bd2"><code>615b319</code></a>
chore: release v6.0.0 for Node.js 24 support</li>
<li><a
href="017748b48f"><code>017748b</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/upload-artifact/issues/744">#744</a>
from actions/fix-storage-blob</li>
<li><a
href="38d4c7997f"><code>38d4c79</code></a>
chore: rebuild dist</li>
<li><a
href="7d27270e0c"><code>7d27270</code></a>
chore: add missing license cache files for <code>@​actions/core</code>,
<code>@​actions/io</code>, and mi...</li>
<li><a
href="5f643d3c94"><code>5f643d3</code></a>
chore: update license files for <code>@​actions/artifact</code><a
href="https://github.com/5"><code>@​5</code></a>.0.1 dependencies</li>
<li><a
href="1df1684032"><code>1df1684</code></a>
chore: update package-lock.json with <code>@​actions/artifact</code><a
href="https://github.com/5"><code>@​5</code></a>.0.1</li>
<li><a
href="b5b1a91840"><code>b5b1a91</code></a>
fix: update <code>@​actions/artifact</code> to ^5.0.0 for Node.js 24
punycode fix</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/upload-artifact/compare/v5.0.0...v6.0.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/upload-artifact&package-manager=github_actions&previous-version=5.0.0&new-version=6.0.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 12:54:23 -05:00
dependabot[bot]
9c55dca352
Build(deps): Bump actions/cache from 4.3.0 to 5.0.1 (#3915)
Bumps [actions/cache](https://github.com/actions/cache) from 4.3.0 to
5.0.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/releases">actions/cache's
releases</a>.</em></p>
<blockquote>
<h2>v5.0.1</h2>
<blockquote>
<p>[!IMPORTANT]
<strong><code>actions/cache@v5</code> runs on the Node.js 24 runtime and
requires a minimum Actions Runner version of
<code>2.327.1</code>.</strong></p>
<p>If you are using self-hosted runners, ensure they are updated before
upgrading.</p>
</blockquote>
<hr />
<h1>v5.0.1</h1>
<h2>What's Changed</h2>
<ul>
<li>fix: update <code>@​actions/cache</code> for Node.js 24 punycode
deprecation by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1685">actions/cache#1685</a></li>
<li>prepare release v5.0.1 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1686">actions/cache#1686</a></li>
</ul>
<h1>v5.0.0</h1>
<h2>What's Changed</h2>
<ul>
<li>Upgrade to use node24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1630">actions/cache#1630</a></li>
<li>Prepare v5.0.0 release by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1684">actions/cache#1684</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v5...v5.0.1">https://github.com/actions/cache/compare/v5...v5.0.1</a></p>
<h2>v5.0.0</h2>
<blockquote>
<p>[!IMPORTANT]
<strong><code>actions/cache@v5</code> runs on the Node.js 24 runtime and
requires a minimum Actions Runner version of
<code>2.327.1</code>.</strong></p>
<p>If you are using self-hosted runners, ensure they are updated before
upgrading.</p>
</blockquote>
<hr />
<h2>What's Changed</h2>
<ul>
<li>Upgrade to use node24 by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1630">actions/cache#1630</a></li>
<li>Prepare v5.0.0 release by <a
href="https://github.com/salmanmkc"><code>@​salmanmkc</code></a> in <a
href="https://redirect.github.com/actions/cache/pull/1684">actions/cache#1684</a></li>
</ul>
<p><strong>Full Changelog</strong>: <a
href="https://github.com/actions/cache/compare/v4.3.0...v5.0.0">https://github.com/actions/cache/compare/v4.3.0...v5.0.0</a></p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/actions/cache/blob/main/RELEASES.md">actions/cache's
changelog</a>.</em></p>
<blockquote>
<h3>5.0.1</h3>
<ul>
<li>Update <code>@azure/storage-blob</code> to <code>^12.29.1</code> via
<code>@actions/cache@5.0.1</code> <a
href="https://redirect.github.com/actions/cache/pull/1685">#1685</a></li>
</ul>
<h3>5.0.0</h3>
<blockquote>
<p>[!IMPORTANT]
<code>actions/cache@v5</code> runs on the Node.js 24 runtime and
requires a minimum Actions Runner version of <code>2.327.1</code>.
If you are using self-hosted runners, ensure they are updated before
upgrading.</p>
</blockquote>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9255dc7a25"><code>9255dc7</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1686">#1686</a>
from actions/cache-v5.0.1-release</li>
<li><a
href="8ff5423e8b"><code>8ff5423</code></a>
chore: release v5.0.1</li>
<li><a
href="9233019a15"><code>9233019</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1685">#1685</a>
from salmanmkc/node24-storage-blob-fix</li>
<li><a
href="b975f2bb84"><code>b975f2b</code></a>
fix: add peer property to package-lock.json for dependencies</li>
<li><a
href="d0a0e18134"><code>d0a0e18</code></a>
fix: update license files for <code>@​actions/cache</code>,
fast-xml-parser, and strnum</li>
<li><a
href="74de208dcf"><code>74de208</code></a>
fix: update <code>@​actions/cache</code> to ^5.0.1 for Node.js 24
punycode fix</li>
<li><a
href="ac7f1152ea"><code>ac7f115</code></a>
peer</li>
<li><a
href="b0f846b50b"><code>b0f846b</code></a>
fix: update <code>@​actions/cache</code> with storage-blob fix for
Node.js 24 punycode depr...</li>
<li><a
href="a783357455"><code>a783357</code></a>
Merge pull request <a
href="https://redirect.github.com/actions/cache/issues/1684">#1684</a>
from actions/prepare-cache-v5-release</li>
<li><a
href="3bb0d78750"><code>3bb0d78</code></a>
docs: highlight v5 runner requirement in releases</li>
<li>Additional commits viewable in <a
href="https://github.com/actions/cache/compare/v4.3.0...v5.0.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=actions/cache&package-manager=github_actions&previous-version=4.3.0&new-version=5.0.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-12-15 12:54:12 -05:00
Tom Limoncelli
7ab7d147fb
CHORE: Move non-provider code out of /providers (#3916)
# Issue

Fixes https://github.com/StackExchange/dnscontrol/issues/3912

# Resolution

```
#!/bin/sh

# Reset

git fetch origin main
git reset --hard origin/main
git checkout main
git branch -D tlim_moveproviders
git checkout -b tlim_moveproviders
find . -name \*.bak -delete

# Move the *.go files out of providers/

mkdir -p pkg/providers
git mv providers/*.go pkg/providers

# move the _all file out of providers/

git mv providers/_all pkg/providers/_all

# Update the imports (in go.* and the affected files)

sed -i.bak -e 's@"github.com/StackExchange/dnscontrol/v4/providers"@"github.com/StackExchange/dnscontrol/v4/pkg/providers"@g' go.* $(fgrep -lr --include '*.go' '"github.com/StackExchange/dnscontrol/v4/providers"' *)
sed -i.bak -e 's@"../../providers"@"../../pkg/providers"@g' pkg/normalize/capabilities_test.go
sed -i.bak -e 's@"github.com/StackExchange/dnscontrol/v4/providers/_all"@"github.com/StackExchange/dnscontrol/v4/pkg/providers/_all"@g' go.* $(fgrep -lr --include '*.go' '"github.com/StackExchange/dnscontrol/v4/providers/_all"' *)

# Fix the docs

sed -i.bak -e 's@StackExchange/dnscontrol/blob/main/providers/_all/all.go@StackExchange/dnscontrol/blob/main/pkg/providers/_all/all.go@g' documentation/advanced-features/writing-providers.md
sed -i.bak -e 's@StackExchange/dnscontrol/providers@StackExchange/dnscontrol/pkg/providers@g' documentation/advanced-features/writing-providers.md
sed -i.bak -e 's@StackExchange/dnscontrol/v4/providers@StackExchange/dnscontrol/v4/pkg/providers@g' documentation/advanced-features/writing-providers.md
sed -i.bak -e 's@dnscontrol/providers/providers.go@dnscontrol/pkg/providers/providers.go@g' documentation/advanced-features/writing-providers.md
sed -i.bak -e 's@providers/_all/all.go@pkg/providers/_all/all.go@g' documentation/advanced-features/writing-providers.md
#sed -i.bak -e 's@@@g' documentation/advanced-features/writing-providers.md
#sed -i.bak -e 's@@@g' documentation/advanced-features/writing-providers.md

find . -name \*.bak -delete

go fmt ./...

git status

echo git commit -a -m'CHORE: Move Non-provider files in providers to pkg/providers'



```
2025-12-15 12:53:52 -05:00
Christopher Hicks
ecbfa9b4a0
CHORE: remove underscores from filenames for consistency (#3909)
## Context

Filenames for providers are not consistent.
https://github.com/StackExchange/dnscontrol/issues/3584#issuecomment-3633894582

## Changes

Rename files:

```
R  documentation/provider/azure_dns.md -> documentation/provider/azuredns.md
R  documentation/provider/azure_private_dns.md -> documentation/provider/azureprivatedns.md
R  documentation/provider/bunny_dns.md -> documentation/provider/bunnydns.md
R  documentation/provider/gandi_v5.md -> documentation/provider/gandiv5.md
R  documentation/provider/hetzner_v2.md -> documentation/provider/hetznerv2.md
R  providers/gandiv5/gandi_v5Provider.go -> providers/gandiv5/gandiv5Provider.go
```

## Verify

- `go build` still works.
- docs generation still works for me locally.
- I see. the Azure docs in the test site for the docs again after
f5767f4

---------

Co-authored-by: Tom Limoncelli <6293917+tlimoncelli@users.noreply.github.com>
2025-12-15 11:51:33 -05:00
Michael Kaye
efe713cc0e
FEATURE: Set --notify via creds.json so that preview or push can always notify (#3910)
Either setting these new options OR using --notify on the commandline
will send notification for any specific execution.

Fixes #3906

In a second commit (feel free to remove) I added some logging to
indicate that notifications were enabled or not (useful when testing
each case).

I've manually tested combinations of the various options, for both
preview and push:
 * --notify set or unset on commandline
 * notify_on_* set to "true" or "ASDAS" or "false" or not mentioned
 
All seem to provide the correct logging line - invalid boolean values
are considered false (not an error).
 
I've made an attempt at documentation of the options, not sure if you
want it elsewhere as well.
  
<!--
## Before submiting a pull request

Please make sure you've run the following commands from the root
directory.

    bin/generate-all.sh

(this runs commands like "go generate", fixes formatting, and so on)

## Release changelog section

Help keep the release changelog clear by pre-naming the proper section
in the GitHub pull request title.

Some examples:
* CICD: Add required GHA permissions for goreleaser
* DOCS: Fixed providers with "contributor support" table
* ROUTE53: Allow R53_ALIAS records to enable target health evaluation

More examples/context can be found in the file .goreleaser.yml under the
'build' > 'changelog' key.
!-->
2025-12-10 12:50:31 -05:00
Tom Limoncelli
6d4a185422
REFACTOR: Run moderize -fix (#3908)
# Issue

We haven't run `moderize` on the codebase in a while. There have been
many updates to the Go language since.

# Resolution

Run it. Test it.
2025-12-09 14:23:26 -05:00
Tom Limoncelli
749db2ca78
CHORE: Linting (#3907)
# Issue

golint and staticcheck reported many linting issues.

# Resolution

Fix them.
2025-12-09 13:01:16 -05:00
Tom Limoncelli
15cae56113
CICD: Update release notes template (#3903)
# Issue

Add to the .goreleaser template:

* Update the list of providers with no maintainer
* Add the meeting reminder

# Resolution

Do it
2025-12-09 11:52:25 -05:00
Tom Limoncelli
0ae4acc3e4
BUGFIX: BIND %D not working after v4.28.0 (#3900)
# Issue

Fixes https://github.com/StackExchange/dnscontrol/issues/3898

After the v4.28.0 upgrade, the `%D` option in BIND's `"filenameformat"`
option no longer works (returns "") when reading the zonefile (but it
works for writing to one!). As a result, "push" always re-creates the
zonefile even if there are no changes.

# Resolution

Fix `%D` in the zone reading code.
2025-12-08 10:32:07 -05:00
Tom Limoncelli
08a6fa6ec4
CHORE: Update deps, regenerate docs (#3902) 2025-12-08 10:13:38 -05:00
Tom Limoncelli
865dad5b78
TOOLS: bin/generate-all.sh should skip .vscode (#3901)
# Issue

bin/generate-all.sh is trying to reformat VSCode's launch.json, but it
can't because it is not strict json.

```
Reformatting: ./.vscode/launch.json
ERROR: Expecting value: line 17 column 17 (char 465)
```

# Resolution

bin/generate-all.sh should skip the .vscode directory.
2025-12-08 10:09:06 -05:00
Christopher Hicks
db27a1e557
[docs] Refresh digital ocean provider docs (#3860)
## Done

- [docs] Refresh digital ocean provider docs by clarifying which record
types are supported, linking to the digital ocean docs, and calling out
other relevant internal docs.
- spelling correction
- update docs for chicks-net as maintainer for digital ocean

## Meta
(Automated in `.just/gh-process.just`.)
2025-12-08 09:14:42 -05:00
Sukka
986bc4c5f4
DOCS: replace all NewRegistrar('ThirdParty') (#3889)
`NewRegistrar("ThirdParty");` has been replaced w/
`NewRegistrar("none");`

The PR updates the docs.
2025-12-05 15:33:03 -05:00
Tom Limoncelli
a0288bd759
bug(split horizon): Domains with split horizons not working (#3895)
Fixes https://github.com/StackExchange/dnscontrol/issues/3894

# Issue

* Split horizon DNS broke in 4.28.0
* Insufficient automated testing to detect this in the future 

# Resolution

* domain.PostProcess() was called twice. The first time the tag was
properly parsed, removing the tag from DomainConfig.Name and putting it
in DomainConfig.Tag. The second time DomainConfig.Name no longer had the
tag and .Tag was set to "".
* The JSON output of DomainConfig doesn't output .UniqueName. If it had,
this bug would have been noticed prior to release. Test updated to
include that field.
2025-12-05 11:41:16 -05:00
Tom Limoncelli
11e9fd138b
CHORE: generate-all.sh (#3892) 2025-12-04 16:50:33 -05:00
Tom Limoncelli
703084160f
REFACTOR: BIND/GANDI_V5 add "RP" record type, rewrite CLOUDFLAREAPI CF_* and more (#3886)
# Issue

* New record type: "RP" (supported by BIND and GANDI_V5) 
* Cloudflare: CF_REDIRECT/CF_TEMP_REDIRECT now generate
CF_SINGLE_REDIRECT records. All PAGE_RULE-based code is removed.
PAGE_RULEs are deprecated at Cloudflare. (be careful when upgrading!)
* New "v2" RecordConfig: RP and CF_SINGLE_REDIRECT are the only record
types that use this method. It shifts most of the work out of JavaScript
and into the Go code, making new record types easier to make, easier to
test, and easier to use by providers. This opens the door to new things
like a potential code-generator for rtypes. Converting existing rtypes
will happen over the next year.
* When only the TTL changes (MODIFY-TTL), the output lists the TTL
change first, not at the end of the line where it is visually lost.
* CF_REDIRECT/CF_TEMP_REDIRECT generate different rule "names". They
will be updated the first time you "push" with this release. The order
of the rules may also change. If you rules depend on a particular order,
be very careful with this upgrade!

Refactoring:

* New "v2" RecordConfig: Record types using this new method simply
package the parameters from dnsconfig.js statements like
CF_REDIRECT(foo,bar) and send them (raw) to the Go code. The Go code
does all processing, validation, etc. and turns them into RecordConfig
that store all the rdata in `RecordConfig.F`. No more adding fields to
RecordConfig for each new record type!
* RecordConfig.IsModernType() returns true if the record uses the new v2
record mechanism.
* PostProcess is now a method on DnsConfig and DomainConfig.
* DOC: How to create new rtypes using the v2 method (incomplete)

Other things:

* Integration tests for CF "full proxy" are removed. This feature
doesn't exist any more.
* DEV: Debugger tips now includes VSCode advice
* TESTING: The names of testgroup's can now have extra spaces to make
data align better
* CF_TEMP_REDIRECT/CF_REDIRECT is now a "builder" that generates
CLOUDFLAREAPI_SINGLE_REDIRECT records.
* And more!

# Resolution

---------

Co-authored-by: Jakob Ackermann <das7pad@outlook.com>
2025-12-04 16:42:20 -05:00
Jiacheng
bcef7f52fc
ALIDNS: Implement ALIDNS Provider (#3878)
<!--
## Before submiting a pull request

Please make sure you've run the following commands from the root
directory.

    bin/generate-all.sh

(this runs commands like "go generate", fixes formatting, and so on)

## Release changelog section

Help keep the release changelog clear by pre-naming the proper section
in the GitHub pull request title.

Some examples:
* CICD: Add required GHA permissions for goreleaser
* DOCS: Fixed providers with "contributor support" table
* ROUTE53: Allow R53_ALIAS records to enable target health evaluation

More examples/context can be found in the file .goreleaser.yml under the
'build' > 'changelog' key.
!-->

https://github.com/StackExchange/dnscontrol/issues/420


Please create the GitHub label 'provider-ALIDNS'

---------

Co-authored-by: Tom Limoncelli <6293917+tlimoncelli@users.noreply.github.com>
2025-12-04 10:55:14 -05:00
Sukka
6153e3bac9
VERCEL: Fix some bugs (#3887)
The PR follows https://github.com/StackExchange/dnscontrol/pull/3542

Found some bugs when running intergration tests locally again, and the
PR is an attempt to fix them:

- When updating/creating HTTPS/SRV records, Vercel API only reads from
the corresponding struct (either `srv` or `https`). If we provide a
`value`, the Vercel API will reject with an error.
- The PR makes `Value` "nil-able", and sets `Value` to nil when dealing
with `SRV` or `HTTPS` records.
- When updating a record, currently, we treat the empty SVC param as
omitting the field. But with Vercel's API, omitting a field means not
updating the field. We need to explicitly make the field an empty string
to create/update an empty SVC param, and the PR does that.
- Vercel implements an unknown `ech=` parameter validation process for
HTTPS records. The validation process is unknown, undocumented, thus I
can't implement a `rejectif` for `AuditRecord`.
- Let's make this a known caveat, describe it in the provider docs, skip
these intergration tests, and move on.

Please tag this PR w/ `provider-VERCEL`.
2025-12-04 10:31:11 -05:00
Tom Limoncelli
7dc81bb4b1
CHORE: FIx lint in diff2 (#3885) 2025-12-04 10:30:19 -05:00
Tom Limoncelli
c11a523982
FEATURE: Fixing IDN support for domains (#3879)
# Issue

The previous fix had backwards compatibility issues and treated
uppercase Unicode incorrectly.

# Resolution

* Don't call strings.ToUpper() on Unicode strings. Only call it on the
output of ToASCII.
* Fix BIND's "filenameformat" to be more compatible (only breaks if you
had uppercase unicode in a domain name... which you probably didn't)
* Change IDN to ASCII in most places (Thanks for the suggestion,
@KaiSchwarz-cnic!)
* Update BIND documentation
2025-12-03 20:31:59 -05:00
Tom Limoncelli
e87f03a8a3
CHORE: fmt (#3882) 2025-12-03 14:53:02 -05:00
Sukka
00f1bd8e85
DOCS: Update Vercel provider docs (#3877)
Made a few mistakes when creating the initial version of the docs back
in #3542

Fix typos, adjust a few wordings, descriptions, etc.

Co-authored-by: Tom Limoncelli <6293917+tlimoncelli@users.noreply.github.com>
2025-12-03 09:11:16 -05:00
tridion
f1b30a1a04
feat: Add IGNORE_EXTERNAL_DNS() for Kubernetes external-dns coexistence (#3869)s
## Summary

This PR adds a new domain modifier `IGNORE_EXTERNAL_DNS()` that
automatically detects and ignores DNS records managed by Kubernetes
[external-dns](https://github.com/kubernetes-sigs/external-dns)
controller.

**Related Issue:** This addresses the feature request discussed in
StackExchange/dnscontrol#935 (Idea: Ownership system), where
@tlimoncelli indicated openness to accepting a PR for this
functionality.

## Problem

When running DNSControl alongside Kubernetes external-dns, users face a
challenge:

- **external-dns** dynamically creates DNS records based on Kubernetes
Ingress/Service resources
- Users cannot use `IGNORE()` because they cannot predict which record
names external-dns will create
- Using `NO_PURGE()` is too broad - it prevents DNSControl from cleaning
up any orphaned records

The fundamental issue is that `IGNORE()` requires static patterns known
at config-time, but external-dns creates records dynamically at runtime.

## Solution

`IGNORE_EXTERNAL_DNS()` solves this by detecting external-dns managed
records at runtime:

```javascript
D("example.com", REG_CHANGEME, DnsProvider(DSP_MY_PROVIDER),
    IGNORE_EXTERNAL_DNS(),  // Automatically ignore external-dns managed records
    A("@", "1.2.3.4"),
    CNAME("www", "@")
);
```

### How It Works

external-dns uses a TXT record registry to track ownership. For each
managed record, it creates a TXT record like:

- `a-myapp.example.com` → TXT containing
`heritage=external-dns,external-dns/owner=...`
- `cname-api.example.com` → TXT containing
`heritage=external-dns,external-dns/owner=...`

This PR:
1. Scans existing TXT records for the `heritage=external-dns` marker
2. Parses the TXT record name prefix (e.g., `a-`, `cname-`) to determine
the managed record type
3. Automatically adds those records to the ignore list during diff
operations

## Changes

| File | Purpose |
|------|---------|
| `models/domain.go` | Add `IgnoreExternalDNS` field to DomainConfig |
| `pkg/js/helpers.js` | Add `IGNORE_EXTERNAL_DNS()` JavaScript helper |
| `pkg/diff2/externaldns.go` | Core detection logic for external-dns TXT
records |
| `pkg/diff2/externaldns_test.go` | Unit tests for detection logic |
| `pkg/diff2/handsoff.go` | Integrate external-dns detection into
handsoff() |
| `pkg/diff2/diff2.go` | Pass IgnoreExternalDNS flag to handsoff() |
| `commands/types/dnscontrol.d.ts` | TypeScript definitions for IDE
support |
| `documentation/.../IGNORE_EXTERNAL_DNS.md` | User documentation |

## Design Philosophy

This follows DNSControl's pattern of convenience builders (like
`M365_BUILDER`, `SPF_BUILDER`, `DKIM_BUILDER`) that make complex
operations simple. Just as those builders abstract away implementation
details, `IGNORE_EXTERNAL_DNS()` abstracts away the complexity of
detecting external-dns managed records.

## Testing

All unit tests pass:
```
go test ./pkg/diff2/... -v  # Tests detection logic
go test ./pkg/js/...        # Tests JS helpers
go build ./...              # Builds successfully
```

## Caveats Documented

- Only supports TXT registry (the default for external-dns)
- Requires external-dns to use default naming conventions
- May need updates if external-dns changes its registry format

---------

Co-authored-by: Tom Limoncelli <6293917+tlimoncelli@users.noreply.github.com>
2025-12-03 08:56:55 -05:00
Jakob Ackermann
ee47032b05
DESEC: populate zone cache after creating zone (#3332)
Hi @D3luxee!
While reviewing all the `ZoneCreator` implementations, I noticed that
the DESEC provider has an incomplete caching implementation for zones.
The provider is populating the cache once on first access. Any zones
that are created will not be readable in the same life-cycle of
dnscontrol. This PR is populating the zone cache after creating a zone.
Would you mind giving this a try and let me know how it goes? Thanks!

Part of https://github.com/StackExchange/dnscontrol/issues/3007
2025-12-03 08:36:29 -05:00
Jakob Ackermann
d1765b6f58
CLOUDNS: populate zone cache when creating zone (#3331)
Hi @pragmaton!
While reviewing all the `ZoneCreator` implementations, I noticed that
the CLOUDNS provider has an incomplete caching implementation for zones.
The provider is populating the cache once on first access. Any zones
that are created will not be readable in the same life-cycle of
dnscontrol. This PR is populating the zone cache after creating a zone.
Would you mind giving this a try and let me know how it goes? Thanks!

Part of https://github.com/StackExchange/dnscontrol/issues/3007
2025-12-03 08:36:00 -05:00
Jakob Ackermann
7b81878a49
ROUTE53: make caching of zones thread-safe (#3328)
Hi @tresni!
While reviewing all the `ZoneCreator` implementations, I noticed that
the ROUTE53 provider has an unsafe caching implementation for zones and
`EnsureZoneExists` has a race-condition bug. `EnsureZoneExists` resets
the cache before making the API call for creating a given zone. This
might run concurrently to the processing of other zones and in turn
could result in unexpected behavior: the cache could get re-populated
before the creation of the zone completes and the new zone could be
missing from the newly populated cache. This PR is making all access to
the zone cache thread-safe and fixing the aforementioned race-condition.
Would you mind giving this a try and let me know how it goes? Thanks!

Bonus: The zone cache is no longer reset when creating zones. Instead,
the cache is populated with the zone that is included in the API
response from creating the zone.

Part of https://github.com/StackExchange/dnscontrol/issues/3007
2025-12-03 08:35:24 -05:00
Tom Limoncelli
b8f2167bf9
BUGFIX: Reverse order of domain ascii/unicode displayed (#3872)
# Issue

Consensus in https://github.com/StackExchange/dnscontrol/pull/2874 is
that the domains should be displayed as:

    xn--p1ai.com (рф.com)
2025-12-02 10:47:11 -05:00
Tom Limoncelli
efa2e1e751
DEV: Add tool to reset js/parse_tests data (#3874)
# Issue

Add tool to reset js/parse_tests data gets out of date easily. Manually
updating it sucks.

# Resolution

Publish a script that copies the "actual" data to the "want" data. DO
NOT CHECK IN THE RESULTS WITHOUT CAREFUL REVIEW.
2025-12-02 10:46:28 -05:00
Tom Limoncelli
4d7774432a
CICD(golangci) Disable errcheck (#3873)
# Issue

errcheck has too many false positives

# Resolution

Disable globally for now.
2025-12-02 10:26:56 -05:00
Tom Limoncelli
93535541a5
CHORE: Update dependencies (#3871) 2025-12-02 09:28:05 -05:00
Jakob Ackermann
abe96b1900
DEPS: Upgrade shoutrrr dependency and remove Go toolchain pinning (#3858)
- Follow up for
https://github.com/StackExchange/dnscontrol/pull/3838#discussion_r2539801899

github.com/nicholas-fedor/shoutrrr < 0.12.1 was pinning the toolchain.
Which in turn required dnscontrol to pin it as well.

This has been fixed upstream via

- https://github.com/nicholas-fedor/shoutrrr/pull/464

and this PR is adopting the [following upstream
release](https://github.com/nicholas-fedor/shoutrrr/releases/tag/v0.12.1).

@gvengel Could you help with testing this PR? Thanks in advance!


<!--
## Before submiting a pull request

Please make sure you've run the following commands from the root
directory.

    bin/generate-all.sh

(this runs commands like "go generate", fixes formatting, and so on)

## Release changelog section

Help keep the release changelog clear by pre-naming the proper section
in the GitHub pull request title.

Some examples:
* CICD: Add required GHA permissions for goreleaser
* DOCS: Fixed providers with "contributor support" table
* ROUTE53: Allow R53_ALIAS records to enable target health evaluation

More examples/context can be found in the file .goreleaser.yml under the
'build' > 'changelog' key.
!-->

Co-authored-by: Tom Limoncelli <6293917+tlimoncelli@users.noreply.github.com>
2025-12-02 09:02:53 -05:00
Tom Limoncelli
0c5d4eac75
CHORE: Update dependencies (#3868) 2025-12-02 09:00:42 -05:00
Patrik Kernstock
6e42ccfb31
INWX: Enable concurrency support (#3856)
Tested dnscontrol with `CanConcur()` enabled and seems to work fine.
Read #2873 to see what to do, and hope below is the right way to test.

```text
$ go build -race -o dnscontrol-race
$ ./dnscontrol-race version
v4.27.2-0.20251127184623-cf6b870052c0+dirty

$ dnscontrol-race preview
CONCURRENTLY checking for 16 zone(s)
SERIALLY checking for 6 zone(s)
Serially checking for zone: "domainX.tld"
Serially checking for zone: "domainX.tld"
Serially checking for zone: "domainX.tld"
Serially checking for zone: "domainX.tld"
Serially checking for zone: "domainX.tld"
Serially checking for zone: "domainX.tld"
Waiting for concurrent checking(s) to complete...DONE
CONCURRENTLY gathering records of 16 zone(s)
SERIALLY gathering records of 6 zone(s)
Serially Gathering: "domainX.tld"
Serially Gathering: "domainX.tld"
Serially Gathering: "domainX.tld"
Serially Gathering: "domainX.tld"
Serially Gathering: "domainX.tld"
Serially Gathering: "domainX.tld"
Waiting for concurrent gathering(s) to complete...DONE
******************** Domain: domainX.tld
INFO#1: 4 records not being deleted because of NO_PURGE:
[...]
******************** Domain: domainX.tld
******************** Domain: domainX.tld
INFO#1: 4 records not being deleted because of NO_PURGE:
[...]
******************** Domain: domainX.tld
******************** Domain: domainX.tld
******************** Domain: domainX.tld
1 correction (PK-INWX)
INFO#1: 1 records not being deleted because of IGNORE*():
[...]
******************** Domain: domainX.tld
******************** Domain: domainX.tld
******************** Domain: domainX.tld
******************** Domain: domainX.tld
30 corrections (PK-INWX)
[...]
******************** Domain: domainX.tld
******************** Domain: domainX.tld
2 corrections (PK-INWX)
[...]
******************** Domain: domainX.tld
******************** Domain: domainX.tld
******************** Domain: domainX.tld
******************** Domain: domainX.tld
2 corrections (PK-INWX)
[...]
******************** Domain: domainX.tld
******************** Domain: domainX.tld
Done. 37 corrections.
```

Unfortunately INWX sandbox is sporadically still broken so `go test` is
of limited help:
```text
$ go test -v -verbose -profile INWX
=== RUN   TestDNSProviders
Testing Profile="INWX" (TYPE="INWX")
    helpers_test.go:122: INWX: Unable to login
--- FAIL: TestDNSProviders (30.03s)
=== RUN   TestDualProviders
Testing Profile="INWX" (TYPE="INWX")
    provider_test.go:50: Clearing everything
    provider_test.go:57: Adding test nameservers
    provider_test.go:44: #1:
        + CREATE dnscontrol-inwx.com NS ns1.example.com. ttl=300
    provider_test.go:44: #2:
        + CREATE dnscontrol-inwx.com NS ns2.example.com. ttl=300
    provider_test.go:60: Running again to ensure stability
    provider_test.go:76: Removing test nameservers
    provider_test.go:44: #1:
        - DELETE dnscontrol-inwx.com NS ns1.example.com. ttl=300
    provider_test.go:44: #2:
        - DELETE dnscontrol-inwx.com NS ns2.example.com. ttl=300
--- PASS: TestDualProviders (2.44s)
=== RUN   TestNameserverDots
Testing Profile="INWX" (TYPE="INWX")
=== RUN   TestNameserverDots/No_trailing_dot_in_nameserver
--- PASS: TestNameserverDots (0.30s)
    --- PASS: TestNameserverDots/No_trailing_dot_in_nameserver (0.00s)
=== RUN   TestDuplicateNameservers
Testing Profile="INWX" (TYPE="INWX")
    provider_test.go:145: Skipping. Deduplication logic is not implemented for this provider.
--- SKIP: TestDuplicateNameservers (0.35s)
FAIL
exit status 1
FAIL    github.com/StackExchange/dnscontrol/v4/integrationTest  33.127s
```
2025-12-01 09:13:06 -05:00
Kevin Ji
ec9a9e23af
CLOUDFLARE: Add LOC support (#3857)
Fixes #2798.

I tested this locally and it seems to update the `LOC` record correctly.
2025-12-01 09:12:10 -05:00
Jakob Ackermann
c073f2e654
HETZNER: gracefully handle FQDN labels when listing records (#3859)
- Closes https://github.com/StackExchange/dnscontrol/issues/3853

This PR is gracefully handling FQDN labels when listing records from the
Hetzner DNS Control api.

These records can be created via other tools or the browser UI.

Testing:

```diff
diff --git a/providers/hetzner/types.go b/providers/hetzner/types.go
index 964f1b7b..3429acc2 100644
--- a/providers/hetzner/types.go
+++ b/providers/hetzner/types.go
@@ -3,2 +3,3 @@ package hetzner
 import (
+       "fmt"
        "strings"
@@ -63,3 +64,3 @@ func fromRecordConfig(in *models.RecordConfig, zone zone) record {
        r := record{
-               Name:   in.GetLabel(),
+               Name:   in.GetLabelFQDN() + ".",
                Type:   in.Type,
@@ -69,2 +70,3 @@ func fromRecordConfig(in *models.RecordConfig, zone zone) record {
        }
+       fmt.Printf("CREATE: %q\n", r.Name)
 
@@ -93,2 +95,3 @@ func toRecordConfig(domain string, r *record) (*models.RecordConfig, error) {
        }
+       fmt.Printf("LISTING: %q\n", r.Name)
        if strings.HasSuffix(r.Name, "."+domain+".") {
```

Config:
```js
var REG_NONE = NewRegistrar('none')
var DSP = NewDnsProvider("HETZNER")

D('testing1.dev', REG_NONE, DnsProvider(DSP),
  A('@', '127.0.0.1'),
  A('foo', '127.0.0.1')
)
```

First push:
```
Waiting for concurrent gathering(s) to complete...LISTING: "@"
LISTING: "@"
LISTING: "@"
LISTING: "@"
CREATE: "foo.testing1.dev."
DONE
******************** Domain: testing1.dev
1 correction (HETZNER)
#1: Batch creation of records:
	+ CREATE A foo.testing1.dev 127.0.0.1 ttl=300
SUCCESS!
Done. 1 corrections.
```

Second push (no-op):
```
Waiting for concurrent gathering(s) to complete...LISTING: "@"
LISTING: "@"
LISTING: "@"
LISTING: "@"
LISTING: "foo.testing1.dev."
DONE
******************** Domain: testing1.dev
Done. 0 corrections.
```

DNS query:
```
$ dig foo.testing1.dev. @helium.ns.hetzner.de.
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 53563
foo.testing1.dev.	300	IN	A	127.0.0.1
```

Additional testing:
- update/delete `foo`  when record `foo.testing1.dev.` exists, works
- creating `foo.testing1.dev` is treated as
`foo.testing1.dev.testing1.dev.` in the API, hence the specific suffix
check for `<dot>DOMAIN<dot>`
- Test with HETZNER_V2, rejects records with FQDN

```
FAILURE! has dot (.) suffix (invalid_input, 50f9cf872ed8f1f808fd33c25cf88a81)
```

<!--
## Before submiting a pull request

Please make sure you've run the following commands from the root
directory.

    bin/generate-all.sh

(this runs commands like "go generate", fixes formatting, and so on)

## Release changelog section

Help keep the release changelog clear by pre-naming the proper section
in the GitHub pull request title.

Some examples:
* CICD: Add required GHA permissions for goreleaser
* DOCS: Fixed providers with "contributor support" table
* ROUTE53: Allow R53_ALIAS records to enable target health evaluation

More examples/context can be found in the file .goreleaser.yml under the
'build' > 'changelog' key.
!-->
2025-12-01 09:08:43 -05:00
Sukka
daf5a7a501
VERCEL: Implement Vercel DNS Provider (#3379) (#3542)
Fixes https://github.com/StackExchange/dnscontrol/issues/3379

Thanks to @SukkaW for adding this provider!  Even though you claimed to be "not familiar with Go at all" the new code looks excellent!  Great job!
2025-12-01 08:41:56 -05:00
Jakob Ackermann
1e67585e8f
HETZNER_V2: Add provider for Hetzner DNS API (#3837)
Closes https://github.com/StackExchange/dnscontrol/issues/3787

This PR is adding a `HETZNER_V2` provider for the "new" Hetzner DNS API.

Testing:
- The integration tests are passing.
- Manual testing:
  - `preview` (see diff for existing zone)
- `preview --populate-on-preview` (see full diff for newly created zone)
  - `push` (see full diff; no diff after push)
- `push` (see full diff; no diff after push to newly created zone --
i.e. single pass and done)

```js
var REG_NONE = NewRegistrar('none')
var DSP = NewDnsProvider('HETZNER_V2')

D('testing-2025-11-14-7.dev', REG_NONE, DnsProvider(DSP),
    A('@', '127.0.0.1')
)
```

<details>

```
# push for newly created zone
CONCURRENTLY checking for 1 zone(s)
SERIALLY checking for 0 zone(s)
Waiting for concurrent checking(s) to complete...DONE
******************** Domain: testing-2025-11-14-7.dev
1 correction (HETZNER_V2)
#1: Ensuring zone "testing-2025-11-14-7.dev" exists in "HETZNER_V2"
SUCCESS!
CONCURRENTLY gathering records of 1 zone(s)
SERIALLY gathering records of 0 zone(s)
Waiting for concurrent gathering(s) to complete...DONE
******************** Domain: testing-2025-11-14-7.dev
4 corrections (HETZNER_V2)
#1: ± MODIFY-TTL testing-2025-11-14-7.dev NS helium.ns.hetzner.de. ttl=(3600->300)
± MODIFY-TTL testing-2025-11-14-7.dev NS hydrogen.ns.hetzner.com. ttl=(3600->300)
± MODIFY-TTL testing-2025-11-14-7.dev NS oxygen.ns.hetzner.com. ttl=(3600->300)
SUCCESS!
#2: + CREATE testing-2025-11-14-7.dev A 127.0.0.1 ttl=300
SUCCESS!
Done. 5 corrections.
```
</details>

Feedback for @jooola and @LKaemmerling:
- The SDK was very useful in getting 80% there! Nice! 🎉 
- Footgun:
- The `result` values are not "up-to-date" after waiting for an
`Action`, e.g. `Zone.AuthoritativeNameservers.Assigned` is not set when
`Client.Zone.Create()` returns and the following "wait" will not update
it.
- Taking a step back here: Waiting for an `Action` with a separate SDK
call does not seem very natural to me. Does the SDK-user need to know
that you are processing operations asynchronous? (Which seems like an
implementation detail to me, something that the SDK could abstrct over.)
Can `Client.Zone.Create()` return the final `Zone` instead of the
intermediate result?
- Features missing compared to the DNS Console, in priority order:
- It is no longer possible to remove your provided name servers from the
root/apex. Use-case: dual-home/multi-home zone with fewer than three
servers from Hetzner. I'm operating one of these and cannot migrate over
until this is fixed.
- Performance regression due to lack of bulk create/modify. E.g. [one of
the test
suites](a71b89e5a2/integrationTest/integration_test.go (L619))
spends about 4.5 minutes on making creating 100 record-sets and then
another 4 minutes for deleting them in sequence again. With your async
API, these are `create 2*100 + delete 2*100 = 400` API calls.
Previously, these were `create 1 + delete 100 = 101` API calls. Are you
planning on adding batch processing again?
- Usability nits
- Compared to other record-set based APIs, upserts for record-sets are
missing. This applies to records of a record-set and the ttl of the
record-set (see separate SDK calls for the cases `diff2.CREATE` vs
`diff2.CHANGE` and two calls in `diff2.CHANGE` for updating the TTL vs
records).
- Some SDK methods return an `Action` (e.g. `Zone.ChangeRRSetTTL()`),
others wrap the `Action` in a struct (`Client.Zone.CreateRRSet()`) --
even when the struct has a single field (`ZoneRRSetDeleteResult`).

---------

Co-authored-by: "Jonas L." <jooola@users.noreply.github.com>
Co-authored-by: "Lukas Kämmerling" <LKaemmerling@users.noreply.github.com>
Co-authored-by: Tom Limoncelli <6293917+tlimoncelli@users.noreply.github.com>
2025-11-30 09:14:54 -05:00