Skip to content

feat: NEW PROVIDER: MITTWALD (Mittwald mStudio provider) - #4933

Merged
TomOnTime merged 6 commits into
DNSControl:mainfrom
mittwald:feat/mittwald-provider
Sep 27, 2026
Merged

TomOnTime merged 6 commits into
DNSControl:mainfrom
mittwald:feat/mittwald-provider

Conversation

@twiesing

Copy link
Copy Markdown
Contributor

Adds MITTWALD, a DNS provider for mittwald mStudio, built on the official Go client github.com/mittwald/api-client-go.

Please create the GitHub label 'provider-MITTWALD'.

How it maps to mStudio

  • mStudio keeps one DNS zone per name (example.com, www.example.com, _dmarc.example.com are separate zones), each with one record set per type: A and AAAA together, CNAME, MX, TXT, SRV, CAA. Corrections are therefore computed with diff2.ByLabel; a name's zone is created when its first record is added and deleted when its last record is removed.
  • Record sets that mStudio manages (addresses of a name connected to an ingress, mittwald's mail exchangers) are neither returned nor touched. Declaring A/AAAA/MX records on such a name replaces the managed set.
  • auditrecords.go rejects what the API does not accept: wildcard names, NS, null MX, MX preference above 100, empty TXT, TXT with trailing space, CAA values other than a host name, TTLs outside 60..86400, and more records per set than the API allows.

API behaviour handled in the transport (retry.go)

  • Rate limit: 3000 requests per 600 s per user. The provider reads X-Ratelimit-Remaining/X-Ratelimit-Reset and waits for the reset once the limit is used up; a 429 (which carries no reset information) is repeated with backoff.
  • Eventual consistency: writes return an event ID (ETag); every following request sends it as If-Event-Reached, so reads see the write and writes to a zone just created find it. 412 is repeated; after a write, 403/404 are repeated a few times, as mittwald's own client does.
  • 5xx are repeated for requests that cannot create anything twice (never for POST).
  • The generated client decodes an unset record set ({}) into several oneOf alternatives at once; sets are only read when they are not unset (regression test included).

Tests

  • Integration tests (go test ./integrationTest -args -profile MITTWALD): 217 passed, run several times.
  • Unit tests for conversion, audit rules and the transport; provider conversion golden files recorded from a passing integration run. Zone IDs and the test domain in the recordings were replaced with neutral values (00000000-…, mittwald-test.example); the replay does not depend on them.
  • go vet, golangci-lint (0 issues), go generate, go mod tidy.

I'll maintain the provider (@twiesing).

@twiesing
twiesing marked this pull request as ready for review September 22, 2026 22:00
@TomOnTime

Copy link
Copy Markdown
Collaborator

Thank you for contributing this new provider, @twiesing !

A few action items before we can merge this PR:

  1. By now you should have received a Github invite to join the Provider-maintainers github team, which gives you the "triage" role for this repo. Please accept the invite so we can assign bugs to you.
  2. @fm: Faisal Misle is our “liaison to maintainers”. Please send him an email from your preferred address to dnscontrol so we can stay in touch. Your email address will not be shared, only used for DNSControl communication. Please email f at faisal dot fm and CC tal at what exit dot org
  3. Please consider setting up a test account for use by our automated testing. This will mean we can test the provider every release in an automated manner. Info is here: https://docs.dnscontrol.org/developer-info/byo-secrets#donate-secrets-to-the-project (If a test account or OE&T environment isn't available, an API key restricted to a single domain is sufficient.)

When I see the Github invite accepted and receive the email, I’ll merge this PR.

Thanks again!
Tom

@TomOnTime TomOnTime left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Thanks for submitting this!

@TomOnTime

Copy link
Copy Markdown
Collaborator

Please rebase.

@twiesing
twiesing force-pushed the feat/mittwald-provider branch from acb68e6 to 7fe1610 Compare September 26, 2026 14:55
@twiesing

Copy link
Copy Markdown
Contributor Author

Rebased onto main.

@TomOnTime TomOnTime changed the title feat(p/MITTWALD): add mittwald mStudio provider feat: NEW PROVIDER: MITTWALD (Mittwald mStudio provider) Sep 27, 2026
@TomOnTime

Copy link
Copy Markdown
Collaborator

CC @cafferata The list of providers in README.md is difficult to update and causes a lot of branch conflicts. Can we generate that list instead?

DNS provider for mittwald mStudio (MITTWALD), using the official client
github.com/mittwald/api-client-go.

mStudio keeps one DNS zone per name, each with one record set per type
(A and AAAA together, CNAME, MX, TXT, SRV, CAA), so changes are made per
label with diff2.ByLabel. Record sets that mStudio manages (ingress
addresses, mittwald mail exchangers) are neither returned nor touched.

The transport keeps requests within the rate limit (X-Ratelimit-*),
sends the event of the last write as If-Event-Reached so that reads and
writes see it, and repeats 429, 412, 5xx and, after a write, a few
403/404 responses; POST requests are never repeated on errors that may
have created something.

Integration tests: 217 passed against a test domain.
…ched

The API also answers a CNAME on a name with other records with 412. That
conflict was repeated like an unprocessed event until the retry budget
ran out; now only a 412 of type FailedPrecondition is repeated.
…ing them

Like other providers with TTL limits, the desired records get a TTL
within 60..86400 before the diff. A and AAAA of one name share one TTL in
mStudio; both get the lower of the two, with a warning, so that the next
run finds no difference.
…eleting a zone

A zone deleted while it has a CAA set leaves the name unable to take a
CAA set ever again (mStudio answers 500); unsetting the set first avoids
this. A zone with other zones below it is no longer deleted.
GET /v2/domains names the project of a domain in one request; only a
domain missing from that list is looked for in the zones of every
project, as before. With a token of a user with many projects this
saves a request per project.
@twiesing
twiesing force-pushed the feat/mittwald-provider branch from 7fe1610 to 8e3bb38 Compare September 27, 2026 13:52
@twiesing

Copy link
Copy Markdown
Contributor Author

Rebased again @TomOnTime 😄 🚀

@TomOnTime
TomOnTime merged commit 966e4cf into DNSControl:main Sep 27, 2026
13 checks passed
@TomOnTime

Copy link
Copy Markdown
Collaborator

Welcome to the team!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

3 participants