Skip to content

nsmaster Knot migration#1208

Draft
peterthomassen wants to merge 16 commits into
mainfrom
20260525_nsmaster_knot
Draft

nsmaster Knot migration#1208
peterthomassen wants to merge 16 commits into
mainfrom
20260525_nsmaster_knot

Conversation

@peterthomassen
Copy link
Copy Markdown
Member

No description provided.

peterthomassen and others added 16 commits May 24, 2026 18:54
Updates the requirements on [psycopg[binary]](https://github.com/psycopg/psycopg) to permit the latest version.
- [Changelog](https://github.com/psycopg/psycopg/blob/master/docs/news.rst)
- [Commits](psycopg/psycopg@3.3.2...3.3.4)

---
updated-dependencies:
- dependency-name: psycopg[binary]
  dependency-version: 3.3.4
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Updates the requirements on [responses](https://github.com/getsentry/responses) to permit the latest version.
- [Release notes](https://github.com/getsentry/responses/releases)
- [Changelog](https://github.com/getsentry/responses/blob/master/CHANGES)
- [Commits](getsentry/responses@0.25.8...0.26.0)

---
updated-dependencies:
- dependency-name: responses
  dependency-version: 0.26.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Updates the requirements on [django-netfields](https://github.com/jimfunk/django-postgresql-netfields) to permit the latest version.
- [Changelog](https://github.com/jimfunk/django-postgresql-netfields/blob/master/CHANGELOG)
- [Commits](jimfunk/django-postgresql-netfields@v1.3.2...v1.4.1)

---
updated-dependencies:
- dependency-name: django-netfields
  dependency-version: 1.4.1
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Updates the requirements on [coverage](https://github.com/coveragepy/coveragepy) to permit the latest version.
- [Release notes](https://github.com/coveragepy/coveragepy/releases)
- [Changelog](https://github.com/coveragepy/coveragepy/blob/main/CHANGES.rst)
- [Commits](coveragepy/coveragepy@7.13.4...7.14.0)

---
updated-dependencies:
- dependency-name: coverage
  dependency-version: 7.14.0
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
- nsmaster/entrypoint.sh: remove 'pdnsutil import-tsig-key' call;
  the DESECSTACK_NSMASTER_TSIGKEY variable is unused (no external
  secondaries currently require TSIG authentication)
- nsmaster/conf/pdns.conf.var: drop ',${DESECSTACK_NSMASTER_ALSO_NOTIFY}'
  from also-notify; hardcoded multicast address 239.1.2.3 is kept
- api/desecapi/pdns.py: remove master_tsig_key_ids from
  create_zone_master() since the key no longer exists in nsmaster
- docker-compose.yml: remove DESECSTACK_NSMASTER_TSIGKEY and
  DESECSTACK_NSMASTER_ALSO_NOTIFY from nsmaster service environment

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ation (Step 1)

export-zones.sh: runs inside the existing PowerDNS nsmaster container;
uses pdnsutil to dump every zone to bind-format zone files and writes a
manifest. catalog.internal is skipped — Knot generates it natively.

import-zones.sh: runs inside the new Knot nsmaster container; registers
all zones in a single knotc conf-begin/conf-commit transaction from the
manifest, pre-loads the exported zone files, and triggers a reload.
catalog.internal is not imported as it is declared statically in
knot.conf with catalog-role: generate.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dockerfile:
- Switch base image from ubuntu:jammy (PowerDNS) to debian:bookworm-slim
- Install Knot DNS from the CZ.NIC vendor apt repository (knot, knot-dnsutils)
- Include iproute2, iptables, gettext-base (same runtime deps as before)
- libknot Python package is NOT installed here — it belongs in the api
  container which is the only service calling the control socket

conf/knot.conf.var (new):
- server: listen on 0.0.0.0/:: port 53; config-db at /var/lib/knot/confdb
- acl: allow 10.8.0.0/24 (VPN secondaries) to transfer
- remote nslord: ${DESECSTACK_IPV4_REAR_PREFIX16}.1.11@53
- remote notify-multicast: 239.1.2.3@53 (preserved from old also-notify)
- template slave: master=nslord, notify=multicast, catalog-zone=catalog.internal.
  zonefile-sync=-1 (journal-only), zonefile-load=whole (bootstrap from file)
- zone catalog.internal.: catalog-role=generate (auto-populated by Knot)

conf/pdns.conf.var: removed (no longer referenced by Dockerfile)

entrypoint.sh:
- Remove PostgreSQL readiness wait and TSIG provisioning
- Use envsubst to render knot.conf.var → /etc/knot/knot.conf
- Create /var/lib/knot and /run/knot with correct ownership
- chmod 777 /run/knot so the api container can reach the control socket
- umask 0 before exec knotd so the socket is created world-accessible

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…master (Steps 3+4d)

Services:
- Remove dbmaster service and its dbmaster_postgres volume reference;
  Knot stores zone data in its own journal (nsmaster_knot volume)
- nsmaster: drop depends_on dbmaster; drop rearmaster network; drop env vars
  DESECSTACK_DBMASTER_PASSWORD_pdns / DESECSTACK_NSMASTER_APIKEY /
  DESECSTACK_NSMASTER_CARBONSERVER / DESECSTACK_NSMASTER_CARBONOURNAME;
  add volumes nsmaster_knot (journal/confdb), nsmaster_socket (control
  socket), zones-export bind-mount (read-only, used once at import time)
- api: add nsmaster_socket volume mount at /run/knot; replace
  DESECSTACK_NSMASTER_APIKEY env var with DESECSTACK_NSMASTER_SOCKET
- celery-email: remove DESECSTACK_NSMASTER_APIKEY (celery workers handle
  email only and do not interact with nsmaster)

Networks:
- Remove rearmaster network definition (172.16.4.0/24); nsmaster no
  longer connects to a Postgres backend

Volumes:
- Remove dbmaster_postgres
- Add nsmaster_knot and nsmaster_socket

.gitignore:
- Add /zones-export/ to avoid accidentally committing exported zone files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…p 6b–6g)

api/desecapi/knot.py (new):
- Thin wrapper around libknot.control.KnotCtl for zone management on nsmaster
- create_zone(name): conf-begin / conf-set zone + template / conf-commit
- delete_zone(name): conf-begin / conf-unset zone / conf-commit
- retrieve_zone(name): zone-retransfer (replaces axfr-retrieve HTTP PUT)
- get_serials(): zone-status, returns {zone: serial} dict
- SOCKET_PATH read from DESECSTACK_NSMASTER_SOCKET env var

api/desecapi/pdns.py:
- Remove NSMASTER sentinel and its _config entry
- Remove create_zone_master, delete_zone_master (→ knot.py)
- Remove axfr_to_master (→ knot.retrieve_zone)
- Remove update_catalog, construct_catalog_rrset (Knot handles catalog)
- Remove get_serials (→ knot.get_serials)
- Remove unused gethostbyname_cached, sha1 import, socket import

api/desecapi/pdns_change_tracker.py:
- Import knot alongside pdns
- CreateDomain.pdns_do: replace create_zone_master + update_catalog with knot.create_zone
- DeleteDomain.pdns_do: replace delete_zone_master + update_catalog with knot.delete_zone
- __exit__: replace pdns.axfr_to_master with knot.retrieve_zone

api/desecapi/management/commands/check-secondaries.py:
- Replace pdns.get_serials() with knot.get_serials()

api/api/settings.py:
- Remove NSMASTER_PDNS_API, NSMASTER_PDNS_API_TOKEN (no HTTP API on nsmaster)
- Remove CATALOG_ZONE (catalog.internal maintained automatically by Knot)
- Keep PDNS_MAX_BODY_SIZE (still referenced for nslord request size checks)

api/requirements.txt:
- Add libknot~=3.5.0 (matches Knot DNS version from CZ.NIC vendor repo)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…(Step 6h)

.env.dev:
- Remove DESECSTACK_DBMASTER_PASSWORD_pdns (no Postgres backend)
- Remove DESECSTACK_NSMASTER_APIKEY (no HTTP API on nsmaster)
- Remove DESECSTACK_NSMASTER_CARBONSERVER / _CARBONOURNAME (Knot has no
  carbon metric integration)
- Add DESECSTACK_NSMASTER_SOCKET=/run/knot/knot.sock

Management commands:
- Delete align-catalog-zone.py: entirely obsolete; catalog.internal is
  generated and maintained automatically by Knot DNS
- sync-to-pdns.py: replace pdns._pdns_put(NSMASTER, axfr-retrieve)
  with knot.retrieve_zone(); remove the catalog alignment call_command
  (no longer needed)

views/domains.py:
- Change 'from desecapi.pdns import get_serials' to knot.get_serials

Test infrastructure (base.py):
- MockPDNSTestCase.setUp(): remove request_pdns_zone_create(ns='MASTER')
  and request_pdns_zone_axfr() from blanket HTTP mocks; replace with
  mock.patch of desecapi.knot.{create_zone,delete_zone,retrieve_zone,
  get_serials} so tests run without a live Knot socket; mocks available
  as self.mock_knot_{create,delete,retrieve}_zone and
  self.mock_knot_get_serials for assertions
- Remove request_pdns_zone_axfr / request_pdns_update_catalog class
  methods (these represented NSMASTER HTTP calls that no longer exist)
- assertZoneCreation: remove ns='MASTER' zone create expectation; nsmaster
  is notified via socket (mocked above)
- assertZoneDeletion: same
- requests_desec_domain_creation: remove ns='MASTER' create, catalog
  update, and axfr expectations
- requests_desec_domain_deletion: same for delete + catalog + axfr
- requests_desec_domain_creation_auto_delegation: remove axfr expectation
- requests_desec_rr_sets_update: remove axfr expectation
- DynDomainOwnerTestCase: remove request_pdns_zone_axfr override;
  update assertDynDNS12Update to drop axfr expectation

test_pdns_change_tracker.py:
- assertPdnsZoneUpdate: remove request_pdns_zone_axfr; only the nslord
  HTTP update is asserted via assertRequests; knot.retrieve_zone is mocked

test_replication.py:
- Rewrite test_serials to configure self.mock_knot_get_serials instead
  of mocking an HTTP GET to nsmaster

test_dyndns12update.py:
- Remove all 12 self.request_pdns_zone_axfr() calls from assertRequests
  lists (these were checking the now-gone NSMASTER HTTP AXFR trigger)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@peterthomassen peterthomassen force-pushed the 20260525_nsmaster_knot branch from 75bc2d4 to 9ca00f6 Compare May 26, 2026 09:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant