Skip to main content

A Python CLI tool for DNS and domain-provider management.

Project description

donazopy

Pre-release / pre-alpha. The command surface changed in this revision (issue 203) — old commands have been removed and replaced with a unified target notation.

donazopy is a focused Python CLI for local DNS zone-file work and real provider operations.

Supported workflows:

  1. Local zone files — validate, normalize, compare two zones as a change summary.
  2. Provider DNS — load credentials from .env or environment, list/export/import records, copy zones between providers, read/assign nameservers, diff a live zone against a file.

Operational providers today: Cloudflare, GoDaddy, IONOS, and Joker.com (DMAPI). Further providers are tracked in TODO.md.

Installation

uv sync

Python 3.12+, Hatch + hatch-vcs for git-tag-derived versions.

Credentials

Credentials are loaded with python-dotenv:

  • donazopy auto-discovers .env from the current working directory.
  • Pass an explicit file with --dotenv-path=path/to/.env.
  • Real environment variables override .env values.
  • Status output shows presence and source only — secret values are never printed.

Create an ignored .env with the credentials for the provider(s) you use:

CLOUDFLARE_DNS_TOKEN=your-token          # Cloudflare (DNS Read for list/export, DNS Edit for import/copy, Zone Edit for create-zone)
CLOUDFLARE_DNS_ACCOUNT=your-account-id    # Cloudflare, optional — only needed for create-zone when the token spans multiple accounts
GODADDY_API_KEY=your-key                 # GoDaddy
GODADDY_API_SECRET=your-secret
IONOS_API_PUBLIC=your-public-prefix      # IONOS (combined as "{public}.{secret}" in the X-API-Key header)
IONOS_API_SECRET=your-secret
JOKER_API_KEY=your-dmapi-api-key         # Joker.com DMAPI

Run donazopy status to see, per provider, which variables are present and where they came from (values are never printed).

Target notation

Most commands accept a TARGET argument using the notation:

[provider/][domain][:record_type][:host_name][:value]
Example Meaning
example.com that domain on whichever sole operational provider manages it
cloudflare/example.com example.com on Cloudflare specifically
cloudflare/* all domains on Cloudflare
cloudflare/example.com:A A records for example.com
cloudflare/example.com:A:www:1.2.3.4 filtered to a specific host and value
example.com.zone a local zone file (resolved by extension / path heuristics)

* in any filter segment means "no filter". A trailing :TYPE:host:value tuple is optional and defaults to no filtering.

Quick start

# Tool version and operational providers
uv run donazopy version
uv run donazopy providers

# Domains a provider manages
uv run donazopy domains ionos --dotenv-path=.env

# Provider metadata and credential status
uv run donazopy status
uv run donazopy status cloudflare
uv run donazopy status cloudflare/example.com --dotenv-path=.env

# DNS records (with optional record-level filters)
uv run donazopy records cloudflare/example.com --dotenv-path=.env
uv run donazopy records cloudflare/example.com:A --dotenv-path=.env

# Export a live zone as BIND text
uv run donazopy export cloudflare/example.com --dotenv-path=.env
uv run donazopy export cloudflare/example.com --output=example.com.zone --overwrite --skip-ns

# Import BIND zone text into a provider
uv run donazopy import-zone cloudflare/example.com example.com.zone --dotenv-path=.env

# Copy a zone from one provider target to another
uv run donazopy copy cloudflare/example.com cloudflare/example-staging.com --skip-ns
uv run donazopy copy cloudflare/example.com cloudflare/example.com --replace  # wipe dest first
uv run donazopy copy ionos/example.com cloudflare/example.com --skip-ns --replace  # migrate IONOS -> Cloudflare (creates the CF zone if missing)

# Create a hosted zone (Cloudflare)
uv run donazopy create-zone cloudflare/example.com --dotenv-path=.env

# Read or assign nameservers
uv run donazopy nameservers cloudflare/example.com --dotenv-path=.env
uv run donazopy nameservers godaddy/* --dotenv-path=.env          # {domain: [nameserver, ...]} for every domain
uv run donazopy nameservers godaddy/example.com ns1.example.net ns2.example.net   # assign (GoDaddy/Joker only)

# Validate and normalize a local zone file
uv run donazopy validate example.com.zone --origin=example.com.
uv run donazopy normalize example.com.zone --origin=example.com.
uv run donazopy normalize example.com.zone --output=normalized.zone --overwrite

# Diff two zones — each side can be a file path or a provider target
uv run donazopy diff before.zone after.zone --origin=example.com.
uv run donazopy diff cloudflare/example.com example.com.zone

# Diagnose a zone (provider target or local file); add --fix to apply safe repairs
uv run donazopy doctor cloudflare/example.com --dotenv-path=.env
uv run donazopy doctor example.com.zone --origin=example.com.
uv run donazopy doctor cloudflare/example.com --fix --dotenv-path=.env
uv run donazopy doctor cloudflare/example.com --json --dotenv-path=.env
uv run donazopy doctor cloudflare/example.com --fix --dmarc-email=ops@dmarc-service.com --dotenv-path=.env

Command reference

Command Description
donazopy version Print installed version
donazopy providers List operational provider keys
donazopy domains PROVIDER [--dotenv-path=PATH] List the domains/zones a provider manages (PROVIDER may be ionos or ionos/*)
donazopy status [TARGET] [--dotenv-path=PATH] Provider metadata + credential status
donazopy records TARGET [--dotenv-path=PATH] List DNS records (target may include record filters)
donazopy export TARGET [--output=PATH] [--overwrite] [--skip-ns] [--skip-types=A,AAAA,...] [--dotenv-path=PATH] Export zone as BIND text
donazopy import-zone TARGET PATH [--proxied] [--dotenv-path=PATH] Import BIND zone file into provider
donazopy create-zone TARGET [--dotenv-path=PATH] Create a hosted zone for the domain (Cloudflare; idempotent). Other providers raise "not supported" — the zone exists with the domain.
donazopy copy SOURCE DEST [--skip-ns] [--skip-types=...] [--replace] [--create=BOOL] [--dotenv-path=PATH] Copy zone between provider targets; by default the destination zone is created if missing (--create=False to skip)
donazopy nameservers TARGET [NS1 NS2 ...] [--dotenv-path=PATH] Read or assign nameservers
donazopy diff A B [--origin=...] [--dotenv-path=PATH] Diff two zones (file paths or provider targets)
donazopy validate PATH [--origin=...] Validate a local BIND zone file
donazopy normalize PATH [--origin=...] [--output=PATH] [--overwrite] Normalize a local BIND zone file
donazopy doctor TARGET [--fix] [--dmarc-email=ADDR] [--json] [--output=PATH] [--overwrite] [--origin=...] [--dotenv-path=PATH] Diagnose a zone (provider target or local file) for migration artifacts, TXT duplicates, missing email-security records, and CNAME conflicts; with --fix, applies safe repairs and writes a backup. --dmarc-email=ADDR plugs ADDR into the suggested/applied DMARC rua=mailto: and prints the external-destination authorization record when the receiving domain differs from the zone.

Provider matrix

Provider Status
Cloudflare Operational: record listing, BIND export/import, zone copy, nameserver read, credential status. assign_nameservers is "not supported" (Cloudflare DNS cannot set registrar delegation).
GoDaddy Operational: domain list, record listing, BIND export, record import (PATCH/append), delete_all_records, registrar nameserver read and assignment.
IONOS Operational: zone list, record listing, BIND export/import, delete_all_records, apex nameserver read. assign_nameservers is "not supported" (the IONOS DNS API cannot change registrar delegation).
Joker.com (DMAPI) Operational: domain list, virtual DNS zone export/import (Joker↔BIND), delete_all_records, registrar nameserver read and assignment.
AWS Route 53, Google Cloud DNS, Azure DNS, Namecheap, DNSimple, Gandi, Porkbun, Dynadot, Vercel, DigitalOcean, Hetzner, Linode, Vultr, Hosting.com, Hostinger, Bluehost Planned only — not exposed until real adapters and tests exist.

Safety model

  • Zone-file operations are local and deterministic.
  • Output writes refuse to overwrite existing files unless --overwrite is passed.
  • copy --replace deletes all destination records before importing; use with care.
  • Credentials are loaded through python-dotenv and environment variables, then redacted in status output.
  • Unsupported providers are not exposed by donazopy providers; only providers with a real adapter and tests appear.
  • assign_nameservers raises a clear "not supported" error on DNS-only delegation surfaces (Cloudflare, IONOS); use a registrar-capable provider (GoDaddy, Joker) to change delegation.

Documentation

Full docs are built from src_docs/md/ with MkDocs + ProtoDocs + MaterialX:

./docs.sh serve   # live preview at http://127.0.0.1:8000
./docs.sh build   # write static output to docs/

Config: mkdocs/mkdocs.yml. Pre-built output is committed to docs/.

Development commands

uv sync
uvx hatch test
uvx ruff check .
uvx --with pytest --with dnspython --with fire --with httpx --with python-dotenv pyright src tests
python -m compileall src tests
./build.sh

./build.sh runs uvx hatch clean and uvx hatch build. ./publish.sh runs uvx hatch clean, uvx gitnextver, uvx hatch build, then uv publish.

Do not commit provider credentials, .env, .pypirc, or private research material.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

donazopy-1.0.15.tar.gz (922.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

donazopy-1.0.15-py3-none-any.whl (57.6 kB view details)

Uploaded Python 3

File details

Details for the file donazopy-1.0.15.tar.gz.

File metadata

  • Download URL: donazopy-1.0.15.tar.gz
  • Upload date:
  • Size: 922.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for donazopy-1.0.15.tar.gz
Algorithm Hash digest
SHA256 1b167d5b157f668ae72df4eea0afdaf1e7e9cf32bddf30f97bc6ff8acdfbfd32
MD5 8e532bb83c2bd111e8e6bf35b2e0ef24
BLAKE2b-256 1e1ce1b71a2b1b2586c225b9f4192f4eaa84c20e18cbb0c55c8afd15c656307f

See more details on using hashes here.

File details

Details for the file donazopy-1.0.15-py3-none-any.whl.

File metadata

  • Download URL: donazopy-1.0.15-py3-none-any.whl
  • Upload date:
  • Size: 57.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.2 {"installer":{"name":"uv","version":"0.11.2","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for donazopy-1.0.15-py3-none-any.whl
Algorithm Hash digest
SHA256 a0c9485cfdc83888f151f048ef46d0c409d6a219b335c20a043903fb4c936d6d
MD5 3e9a5b89af106e822b63ed2d424c4bdf
BLAKE2b-256 ec6a0b94b2c22081cf5b45e9a0c5e071bee17978f623de8da76980c6c24d996d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page