github PowerDNS/pdns-ansible v1.11.0

3 hours ago

v1.11.0 (24-08-2026)

NEW FEATURES:

  • Provision autoprimaries (pdns_provision_autoprimaries), zones and catalog zones (pdns_provision_zones), records (pdns_provision_records), zone metadata (pdns_provision_zone_metadata), DNSSEC keys (pdns_provision_cryptokeys), TSIG keys (pdns_provision_tsigkeys), view membership (pdns_provision_views) and networks mapped to a view (pdns_provision_networks) through the REST API. Every entry is submitted as written, with only the few keys that build the request URL read by the role and removed from the body, so any field the API accepts can be given whether or not the role knows about it. Provisioning adds and removes nothing: an entry that is already there is left alone, and so is anything on the server that no list mentions (#276)
  • Add pdns_provision_records for the records of a zone, one entry per RRset, with changetype defaulting to REPLACE and DELETE removing an RRset. Zone and record lifecycles are separate resources with separate endpoints, so they are declared separately: records inside a pdns_provision_zones entry only apply when that zone is created. Each entry is compared against the zone before anything is written, which keeps a repeated converge at changed=0 and leaves the SOA serial alone - the serial moves on every PATCH the API receives, including one that changes nothing (#276)
  • Add pdns_provision_pdnsutils, a list of commands run through pdnsutil, for what the REST API cannot do. Each entry takes args and an optional unless probe that makes it safe to repeat, since pdnsutil subcommands are not idempotent by themselves. The commands run as pdns_user rather than root: pdnsutil writes the backend's own files, and root-owned ones leave the unprivileged server unable to write them, which running the role again does not repair. The invocation carries --config-name for an instance, so it cannot silently act on the default one (#276)
  • Add pdns_provision_update_existing to write the declared attributes of a zone entry onto a zone that already exists, and pdns_provision_prune to delete autoprimaries, TSIG keys and view members that the lists do not declare and to unmap an undeclared network. Both default to false. Zones and DNSSEC keys are never deleted whatever pdns_provision_prune is set to (#276)
  • Add pdns_provision_ignore_missing_zone, default true, so that metadata and DNSSEC keys declared for a zone that does not exist are skipped on the API's 404 instead of failing the play (#276)
  • Add pdns_provision_run_once to provision against the first host of the play instead of once per host, for a cluster whose hosts share one database. Off by default, because with a per-host backend - lmdb, bind, or a local gsqlite3 file - running once would leave every host but the first unprovisioned (#276)

IMPROVEMENTS:

  • Normalize the values the API canonicalizes before comparing them, so a repeated converge settles. A TSIG key declared with a trailing dot is stored without one, and a zone kind of native is stored as Native; both used to look different on every run, and the TSIG mismatch repeated the create until the API answered 409 and failed the play (#276)

DEPRECATIONS:

  • pdns_autoprimaries is deprecated in favour of pdns_provision_autoprimaries, the name the rest of the provisioning family uses, and will be removed in the next release. pdns_provision_autoprimaries defaults to pdns_autoprimaries, so a playbook that still sets the old name keeps working, and setting the new name takes precedence (#276)

BREAKING CHANGES:

  • Autoprimaries are no longer removed unless pdns_provision_prune is enabled. Provisioning previously deleted any autoprimary that pdns_autoprimaries did not list, on every converge; it now follows the same rule as every other provisioned resource and removes nothing by default. Set pdns_provision_prune: true to keep the previous behaviour (#276)

IMPROVEMENTS:

  • Skip provisioning under --check instead of failing on it. ansible.builtin.uri has no check mode and aborts the play, and there is nothing to simulate, since provisioning talks to a running instance (#276)
  • Report a provisioning request that ran as changed. ansible.builtin.uri reports changed: false even for a 201, so a converge that created zones and keys used to claim it had changed nothing (#276)
  • Submit an autoprimary entry as written, rather than rebuilding the body from ip, nameserver and account, so the remaining fields of the API are reachable. account still defaults to an empty string, which the API requires (#276)
  • Split the provisioning tasks into one file per resource, included from tasks/provision.yml (#276)
  • Cover provisioning in the same run that changes the API key in the default scenario's side effect. The key is written to the configuration file, so the instance serves the old one until the restart the role flushes before provisioning; without that flush every request is answered 401 (#276)
  • Document provisioning in the README (#276)
  • Read facts through ansible_facts instead of the injected top-level ansible_* variables. ansible-core deprecated that injection and removes it in 2.24, after which a role reading ansible_distribution would break. The Molecule configuration sets inject_facts_as_vars: false, so a missed reference fails a test run instead of surfacing on a future ansible-core (#274)
  • Install python3-pymysql instead of python3-mysqldb on Debian. The MySQL modules warn that support of the MySQLdb connector is deprecated, they stop testing it in collection version 4.0.0 and remove it in 5.0.0. Enterprise Linux and Arch Linux already used PyMySQL, so the three families now agree (#274)
  • Cap every collection in requirements.yml. A collection that raises its requires_ansible in a new major would otherwise break the ansible-core 2.16 leg on the day it is published, without a change in this repository (#274)
  • Manage the service with ansible.builtin.systemd_service instead of ansible.builtin.systemd, matching the module name used by the other PowerDNS roles (#274)
  • Declare Ubuntu 26.04 in the Galaxy metadata (#274)
  • Rework apt and dnf repo file creation to stop using version suffixed file names which are not cleaned up on version changes (#265, @l00d3r)
  • Remove version suffixed apt and dnf repo files (#265, @l00d3r)
  • Document the check mode support (converged hosts only) and the package/service state variables in the README (#271)
  • Document the handler behaviour and the multi-instance usage in the README (#272)

NEW FEATURES:

  • Add pdns_mysql_flavor, mysql or mariadb, to choose which collection creates the database and the user of the gmysql backend: ansible.mysql or ansible.mariadb. The default mysql keeps the current behaviour for every existing user, because ansible.mysql still manages MariaDB, while warning that its support ends in 6.0.0. A MariaDB server can be moved to the collection that keeps supporting it by setting mariadb; nothing else about the backend changes (#274)
  • Add the pdns_auth_powerdns_repo_51 repository preset for the '5.1.x' release series (#274)
  • Add support for provisioning autoprimaries through the PowerDNS API (#265, @NocDerEchte)
  • Add pdns_flush_handlers to run the notified handlers at the end of the role instead of at the end of the play, which is required when the role runs more than once in a play (#272)
  • Add the multi-instance Molecule scenario, which configures two instances in a single play (#272)

BUG FIXES:

  • Skip the restart under --skip-tags service. Ansible filters tasks by tag but not handlers, so a run that deliberately left the service alone still restarted it on a configuration change - and restarting an inactive unit starts it. The handler reads ansible_skip_tags and still reloads the units, so a --tags config run is unaffected (#275)
  • Reload the systemd units in the same task that restarts the service. A restart can no longer run against a unit systemd has not read, and a host left with a drop-in systemd never loaded is repaired by the next change instead of restarting onto the stale unit (#275)
  • Reload the systemd units in the service task when this run changed the drop-in. Handlers flush at the end of the play, so a service that was not running yet was started from the unit systemd had loaded before the run and kept the previous settings until the handler restarted it (#275)
  • Remove /etc/systemd/system/<service name>.service.d/override.conf when pdns_service_overrides is empty, and restart the service. The file used to stay on disk, so emptying the variable kept the previous overrides - including the User and Group of the default value - applied forever. Other drop-ins in that directory are left alone (#275)
  • Remove the drop-in override directory when pdns_package_state: absent, so a later reinstall does not inherit the overrides of the previous installation. The unit it belongs to is being removed, so the whole directory goes; while the package stays installed only the file this role writes is removed (#275)
  • Tag the tasks inside inspect.yml, selinux.yml, database-*.yml and provision.yml, and tag the Set fact for repo name task with install and repository. A dynamic include_tasks does not pass its tags to the tasks it includes, so --tags install and --tags repository failed with 'pdns_auth_repo_regex' is undefined, and --tags backend and --tags selinux silently did nothing (#271)
  • Add check_mode: false to the read-only schema location probes of all three SQL backends and to the MySQL empty-database probe, so --check no longer reasons about schema state from empty registered results (#271)
  • Flush the handlers before provisioning when pdns_provision is enabled. Provisioning calls the API of the running server with the configured address, port and API key, so rotating the API key or changing the webserver port failed with 401 Unauthorized or a refused connection while the pending restart was still queued for the end of the play (#272)
  • Read the service name and state from facts published per role invocation in the restart handlers. Ansible shares handlers between invocations of the same role and resolves role parameters to the last invocation, so a play with more than one instance restarted the wrong service. Correct restarts need pdns_flush_handlers: true as well (#272)
  • Replace community.mysql.mysql_db and community.mysql.mysql_user with ansible.mysql.mysql_db and ansible.mysql.mysql_user. community.mysql 5.x redirects both modules and removes them in 6.0.0, which also made ansible-lint fail on fqcn[canonical] (#271)

BREAKING CHANGES:

  • Require ansible-core 2.16 or later (min_ansible_version 2.15 -> 2.16) and drop the 2.15 CI leg. ansible.mysql declares requires_ansible: '>=2.16.0' (#271)
  • Manage Enterprise Linux 8 targets with ansible-core 2.16 only. Their system Python is 3.6, which ansible-core 2.20 modules cannot run (#274)

REMOVED FEATURES:

  • Remove vars/Ubuntu-20.yml. Ubuntu 20.04 hosts now fall through to vars/Debian.yml, which uses python3-mysqldb instead of python3-pymysql for the MySQL modules. Ubuntu 20.04 itself stays supported and tested against the 4.9 series, the only one upstream publishes focal packages for, with ansible-core 2.16 because of its Python 3.8 (#274)
  • Stop testing the auth-master repository and the 4.8 series, and test the three most recent release series instead. The pdns_auth_powerdns_repo_master and pdns_auth_powerdns_repo_48 presets are unchanged and still usable (#274)
  • Remove the per-backend tags mysql, pgsql, sqlite and lmdb, and rename db to backend. The role tag vocabulary is now repository, install, config, service, backend and selinux. The removed tags never selected the backend tasks anyway (#271)

Don't miss a new pdns-ansible release

NewReleases is sending notifications on new releases.