Repository: PowerDNS/pdns-ansible Branch: master Commit: 1b7d296d0d0f Files: 79 Total size: 181.6 KB Directory structure: gitextract_axlon5gn/ ├── .ansible-lint ├── .github/ │ ├── dependabot.yml │ └── workflows/ │ └── main.yml ├── .gitignore ├── .yamllint ├── CHANGELOG.md ├── LICENSE ├── README.md ├── defaults/ │ └── main.yml ├── handlers/ │ └── main.yml ├── meta/ │ └── main.yml ├── molecule/ │ ├── pdns-48/ │ │ ├── converge.yml │ │ └── molecule.yml │ ├── pdns-49/ │ │ ├── converge.yml │ │ └── molecule.yml │ ├── pdns-50/ │ │ ├── converge.yml │ │ └── molecule.yml │ ├── pdns-master/ │ │ ├── converge.yml │ │ └── molecule.yml │ ├── pdns-os-repos/ │ │ ├── converge.yml │ │ └── molecule.yml │ └── resources/ │ ├── Dockerfile.archlinux-systemd.j2 │ ├── Dockerfile.debian-systemd.j2 │ ├── Dockerfile.el-systemd.j2 │ ├── cleanup.yml │ ├── create.yml │ ├── destroy.yml │ ├── prepare.yml │ ├── tests/ │ │ ├── all/ │ │ │ └── test_common.py │ │ ├── backend-bind/ │ │ │ └── test_backend_bind.py │ │ ├── backend-lmdb/ │ │ │ └── test_backend_lmdb.py │ │ ├── backend-mariadb/ │ │ │ └── test_backend_mariadb.py │ │ ├── backend-mysql/ │ │ │ └── test_backend_mysql.py │ │ ├── backend-postgresql/ │ │ │ └── test_backend_postgresql.py │ │ ├── backend-sqlite/ │ │ │ └── test_backend_sqlite.py │ │ ├── backend-zones/ │ │ │ └── test_backend_zones.py │ │ ├── repo-48/ │ │ │ └── test_repo_48.py │ │ ├── repo-49/ │ │ │ └── test_repo_49.py │ │ ├── repo-50/ │ │ │ └── test_repo_50.py │ │ ├── repo-master/ │ │ │ └── test_repo_master.py │ │ ├── service-mask/ │ │ │ └── test_service_mask.py │ │ ├── systemd-no-override/ │ │ │ └── test_override.py │ │ └── systemd-override/ │ │ └── test_override.py │ └── vars/ │ ├── molecule.yml │ ├── pdns-backend-bind.yml │ ├── pdns-backend-lmdb.yml │ ├── pdns-backend-mariadb.yml │ ├── pdns-backend-mysql.yml │ ├── pdns-backend-postgresql.yml │ ├── pdns-backend-sqlite3.yml │ ├── pdns-common.yml │ ├── pdns-no-overrides.yml │ ├── pdns-os-repos.yml │ ├── pdns-repo-48.yml │ ├── pdns-repo-49.yml │ ├── pdns-repo-50.yml │ └── pdns-repo-master.yml ├── requirements.yml ├── tasks/ │ ├── configure.yml │ ├── database-lmdb.yml │ ├── database-mysql.yml │ ├── database-pgsql.yml │ ├── database-sqlite3.yml │ ├── inspect.yml │ ├── install.yml │ ├── main.yml │ ├── repo-Debian.yml │ ├── repo-RedHat.yml │ └── selinux.yml ├── templates/ │ ├── override-service.systemd.conf.j2 │ ├── pdns.conf.j2 │ └── pdns.pin.j2 ├── test-requirements.txt ├── tox.ini └── vars/ ├── Archlinux.yml ├── Debian.yml ├── RedHat.yml ├── Ubuntu-20.yml └── main.yml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .ansible-lint ================================================ --- skip_list: [] ================================================ FILE: .github/dependabot.yml ================================================ --- # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates version: 2 updates: - package-ecosystem: github-actions directory: "/" schedule: interval: daily timezone: Europe/Amsterdam open-pull-requests-limit: 3 - package-ecosystem: pip directory: "/" schedule: interval: daily timezone: Europe/Amsterdam open-pull-requests-limit: 3 ================================================ FILE: .github/workflows/main.yml ================================================ --- on: push: pull_request: schedule: - cron: '33 5 * * 0' jobs: Lint: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v6 - name: Run ansible-lint uses: ansible/ansible-lint@main Tests: name: Test role on different ansible versions runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: ansible: - "2.15" - "2.16" scenario: - pdns-48 - pdns-49 - pdns-50 - pdns-master - pdns-os-repos steps: - name: checkout uses: actions/checkout@v6 - name: Install python uses: actions/setup-python@v5 with: python-version: "3.11" - name: Install dependencies run: | python -m pip install --upgrade pip pip install tox tox-gh-actions - name: Run the tests run: tox -- molecule test -s ${{ matrix.scenario }} env: ANSIBLE: ${{ matrix.ansible }} ================================================ FILE: .gitignore ================================================ ### Ansible ### *.retry .ansible_cache .ansible ### Python ### # Byte-compiled / optimized / DLL files .pytest_cache/ __pycache__/ *.py[cod] *$py.class ### Molecule ### .tox .cache .molecule .vagrant #venv venv ================================================ FILE: .yamllint ================================================ --- # Based on ansible-lint config extends: default ignore: | .tox/ .git/ .venv/ venv/ .cache/ .pytest_cache/ rules: braces: max-spaces-inside: 1 level: error brackets: max-spaces-inside: 1 level: error colons: max-spaces-after: -1 level: error commas: max-spaces-after: -1 level: error comments: min-spaces-from-content: 1 comments-indentation: disable document-start: enable empty-lines: max: 3 level: error hyphens: level: error indentation: enable key-duplicates: enable line-length: disable new-line-at-end-of-file: enable new-lines: type: unix octal-values: forbid-implicit-octal: true forbid-explicit-octal: true trailing-spaces: disable truthy: allowed-values: ["true", "false"] check-keys: false ================================================ FILE: CHANGELOG.md ================================================ ## v1.10.0 (2026-02-24) NEW FEATURES: - Add role-level package state controls for PowerDNS, debug symbols, backend packages, and backend dependency packages: `pdns_package_state`, `pdns_debug_symbols_package_state`, `pdns_backends_packages_state`, `pdns_mysql_packages_state`, `pdns_pgsql_packages_state`, and `pdns_sqlite_package_state`. - Add role documentation section describing standard tags (`install`, `config`, `service`, `repository`). IMPROVEMENTS: - Add explicit task/handler tags across installation, repository, configuration, and service flows to support predictable partial runs. - Refactor MySQL, PostgreSQL, and SQLite database tasks into clearer management blocks with explicit package-state handling. - Improve role behavior when `pdns_package_state: absent` by skipping runtime configuration/service tasks while still allowing dependency/package removal paths. - Normalize defaults/documentation booleans (`true`/`false`) and fix minor typos. - Include `hostname` in the EL Molecule Docker image package set. ## v1.9.0 (2026-02-23) NEW FEATURES: - Add configuration for flat files ([\#79](https://github.com/PowerDNS/pdns-ansible/pull/79), @sorrowless) - Allow installation of custom scripts ([\#210](https://github.com/PowerDNS/pdns-ansible/pull/210), @zerwes) - Add support and tests for Rocky Linux and AlmaLinux ([\#209](https://github.com/PowerDNS/pdns-ansible/pull/209), @romeroalx) - Add pdns49 repository and CI ([\#213](https://github.com/PowerDNS/pdns-ansible/pull/213), @npmdnl) - Add pdns50 repository and CI ([\#247](https://github.com/PowerDNS/pdns-ansible/pull/247), @npmdnl) - Add PostgreSQL backend provisioning and Molecule coverage (based in [\#216](https://github.com/PowerDNS/pdns-ansible/pull/216) @dtrdnk, [\#211](https://github.com/PowerDNS/pdns-ansible/pull/211) @Exchizz, [\#104](https://github.com/PowerDNS/pdns-ansible/pull/104) @commonism) - Add role-level toggles for PostgreSQL backend bootstrap (`pdns_pgsql_manage_database`, `pdns_pgsql_schema_load`, `pdns_pgsql_schema_on_first_node_only`) - Add role-level SELinux control via `pdns_manage_selinux` (enabled by default) - Add service masking support via `pdns_service_masked` - Add role verbosity toggle (`pdns_verbose`) to control redaction of sensitive SQL task logs - Add architecture-aware APT repository settings for Debian-family systems (`pdns_apt_repo_arch` map with `amd64`/`arm64`) IMPROVEMENTS: - Include `mysql_schema_file` in MySQL import task names ([\#119](https://github.com/PowerDNS/pdns-ansible/pull/119), @zerwes) - Run MySQL database commands on the first node only for clustered setups ([\#120](https://github.com/PowerDNS/pdns-ansible/pull/120), @zerwes) - Remove `nolog` from backend install while still hiding passwords in logs ([\#175](https://github.com/PowerDNS/pdns-ansible/pull/175), @zerwes) - Update `pdns-master` CI configuration and replace Ubuntu Bionic with Focal ([\#207](https://github.com/PowerDNS/pdns-ansible/pull/207), @romeroalx) - Update SQLite3 backend defaults ([\#220](https://github.com/PowerDNS/pdns-ansible/pull/220), @kleini) - Fix CI request handling in GitHub Actions ([\#221](https://github.com/PowerDNS/pdns-ansible/pull/221), @romeroalx) - Upgrade CI tests to newer `molecule` and `ansible-core` versions ([\#230](https://github.com/PowerDNS/pdns-ansible/pull/230), @romeroalx) - Update examples after variable deprecations ([\#240](https://github.com/PowerDNS/pdns-ansible/pull/240), @henkjan) - Add Deb822 APT repository support on Debian-family systems while keeping legacy `apt_repo` compatibility (based on [\#242](https://github.com/PowerDNS/pdns-ansible/pull/242) @l00d3r, [\#246](https://github.com/PowerDNS/pdns-ansible/pull/246) @joshsol1) - Bump `ansible-lint` to 6.18.0 ([\#190](https://github.com/PowerDNS/pdns-ansible/pull/190), @dependabot[bot]) - Rework MySQL bootstrap workflow for MySQL 8.4/9 and MariaDB compatibility: - socket/TCP selection with `pdns_mysql_query_use_socket` and `pdns_mysql_unix_socket` - configurable SQL CLI command/flags via `pdns_backends_mysql_cmd` and `pdns_mysql_cli_extra_args` - auth plugin and password-update controls via `pdns_mysql_auth_plugin` and `pdns_mysql_user_update_password` - Improve PostgreSQL bootstrap workflow with socket/TCP selection and first-node-only execution controls - Improve SQLite schema detection/import by supporting compressed schemas (`.gz`, `.xz`) and additional distro-specific paths - Improve PowerDNS version detection by parsing both stdout/stderr to handle plugin load noise - Consolidate OS variable loading order in role (`os_family` -> `distribution` -> major-version overrides) - Standardize service management on `ansible.builtin.systemd` and apt cache updates through handlers REMOVED / EOL: - Drop pdns46 repository (EOL) ([\#208](https://github.com/PowerDNS/pdns-ansible/pull/208), @npmdnl) - Remove EOL CI targets RHEL 7, Debian 10, and Ubuntu 20.04; add Debian 11, Debian 12, and Ubuntu 24.04 ([\#222](https://github.com/PowerDNS/pdns-ansible/pull/222), @romeroalx, [\#243](https://github.com/PowerDNS/pdns-ansible/pull/243), @romeroalx) - Drop pdns47 repository (EOL) ([\#247](https://github.com/PowerDNS/pdns-ansible/pull/247), @npmdnl) - Remove deprecated named-schema generation role components (`tasks/database-named.yml`, `templates/named.conf.j2`, `templates/named.zone.j2`) - Remove version-specific RedHat vars files in favor of consolidated `vars/RedHat.yml` BUG FIXES: - Reorder `selinux.yml` include to resolve issue #122 ([\#123](https://github.com/PowerDNS/pdns-ansible/pull/123), @pixelrebel) - Add missing closing braces ([\#172](https://github.com/PowerDNS/pdns-ansible/pull/172), @arjenz) - Fix logging for grant access task ([\#195](https://github.com/PowerDNS/pdns-ansible/pull/195), @zerwes) - Fix `pdns-os-repos` CI tests ([\#214](https://github.com/PowerDNS/pdns-ansible/pull/214), @romeroalx) - Add missing RHEL-family packages required for SELinux support ([\#218](https://github.com/PowerDNS/pdns-ansible/pull/218), @vhsantos) - Move PowerDNS restart logic to handlers ([\#244](https://github.com/PowerDNS/pdns-ansible/pull/244), @valiac) - Exclude local `.ansible` cache directory from linting ([\#245](https://github.com/PowerDNS/pdns-ansible/pull/245), @valiac) - Fix SELinux DB-connect boolean activation for both MySQL and PostgreSQL backends (including multi-instance backend names) - Fix MySQL/MariaDB bootstrap on `caching_sha2_password` by adding required `python*-cryptography` dependencies in role defaults ## v1.8.0 (2023-08-03) NEW FEATURES: - Added pdns48 repository and CI ([\#180](https://github.com/PowerDNS/pdns-ansible/pull/180)) - Added support for OL9 ([\#145](https://github.com/PowerDNS/pdns-ansible/pull/145)) - Added pdns47 repository and CI ([\#135](https://github.com/PowerDNS/pdns-ansible/pull/135)) - Replaced Centos8 with OL8 ([\#133](https://github.com/PowerDNS/pdns-ansible/pull/133)) - Added pdns46 repository and CI ([\#117](https://github.com/PowerDNS/pdns-ansible/pull/117)) IMPROVEMENTS: - Bump versions and various fixes in CI and README.md ([\#179](https://github.com/PowerDNS/pdns-ansible/pull/179) - Bump versions in requirements.txt ([\#144](https://github.com/PowerDNS/pdns-ansible/pull/144)) - Removal of deprecation warning ([\#121](https://github.com/PowerDNS/pdns-ansible/pull/121)) - Do not restart all servers at once ([\#109](https://github.com/PowerDNS/pdns-ansible/pull/109)) - Prevent logging of password information ([\#106](https://github.com/PowerDNS/pdns-ansible/pull/106)) REMOVED FEATURES: - Drop pdns45, support for Debian 9 ([\#179](https://github.com/PowerDNS/pdns-ansible/pull/179)) EOL - Drop Ansible v2.9 - v2.10 - v2.11 from CI and removed pdns43 and pdns44 ([\#144](https://github.com/PowerDNS/pdns-ansible/pull/144)) for EOL BUG FIXES: - Add MySQL schema path with PowerDNS 4.6 and Rocky Linux 8 with EPEL package installation ([\#114](https://github.com/PowerDNS/pdns-ansible/pull/114)) ## v1.7.0 (2021-07-01) NEW FEATURES: - Create directory, set the ownership and permissions for LMDB databases ([\#95](https://github.com/PowerDNS/pdns-ansible/pull/95)) - Add database schema file detection on the target system with override possibility ([\#100](https://github.com/PowerDNS/pdns-ansible/pull/100)) - Add 4.4 repositories ([\#91](https://github.com/PowerDNS/pdns-ansible/pull/91)) IMPROVEMENTS: - Use systemd task option `daemon_reload` instead of command task ([\#90](https://github.com/PowerDNS/pdns-ansible/pull/90)) REMOVED FEATURES: - Drop EL6 support ([\#91](https://github.com/PowerDNS/pdns-ansible/pull/91), [\#94](https://github.com/PowerDNS/pdns-ansible/pull/94)) - Remove 4.1 and 4.2 repositories ([\#101](https://github.com/PowerDNS/pdns-ansible/pull/101)) BUG FIXES: - Re-instate molecule tests ([\#100](https://github.com/PowerDNS/pdns-ansible/pull/100)) ## v1.6.1 (2020-10-01) BUG FIXES: - Ensure install does not fail when no overrides are defined ([\#85](https://github.com/PowerDNS/pdns-ansible/pull/85)) - Ensure that `ExecStart` is overridden, not appended to ([\#86](https://github.com/PowerDNS/pdns-ansible/pull/86)) ## v1.6.0 (2020-09-18) BUG FIXES: - Fix path to MySQL schema for Debian 10 ([\#73](https://github.com/PowerDNS/pdns-ansible/pull/73)) IMPROVEMENTS: - Allow loading apt key from the ansible server ([\#75](https://github.com/PowerDNS/pdns-ansible/pull/75)) - CentOS 8 support ([\#74](https://github.com/PowerDNS/pdns-ansible/pull/74), [\#81](https://github.com/PowerDNS/pdns-ansible/pull/81)) - Archlinux support ([\#76](https://github.com/PowerDNS/pdns-ansible/pull/76)) - Set the ownership and permissions for config files and databases ([\#82](https://github.com/PowerDNS/pdns-ansible/pull/82)) - Ensure PowerDNS is started as an unprivileged user by default (in line with PowerDNS 4.3+ behaviour) ## v1.5.0 (2019-12-11) BUG FIXES: - - Fix the restart of the PowerDNS service in case of instances with different `pdns_service_name` being configured in the same play ([\#70](https://github.com/PowerDNS/pdns-ansible/pull/70)) IMPROVEMENTS: - Add support to the PowerDNS 4.3.x release ([\#69](https://github.com/PowerDNS/pdns-ansible/pull/69)) - Add support to the PowerDNS 4.2.x release ([\#61](https://github.com/PowerDNS/pdns-ansible/pull/61)) - Install missing SQLite packages ([\#69](https://github.com/PowerDNS/pdns-ansible/pull/69)) - Improved PowerDNS configuration files and directories permissions handling ([\#69](https://github.com/PowerDNS/pdns-ansible/pull/69)) - Stop interpreting 0 & 1 as no & yes in the PowerDNS configuration template ([\#68](https://github.com/PowerDNS/pdns-ansible/pull/68)) - Fix some strings comparisons and variable types issues reported by ansible-lint ([\#66](https://github.com/PowerDNS/pdns-ansible/pull/66)) - Update the CI infrastructure to test the role against the Ansible 2.7, 2.8 and 2.9 releases ([\#67](https://github.com/PowerDNS/pdns-ansible/pull/67)) - Update the CI infrastructure to stop testing against an EOL Ubuntu release ([\#62](https://github.com/PowerDNS/pdns-ansible/pull/62)) ## v1.4.0 (2018-12-02) BUG FIXES: - Fix handling of lists expansion in the PowerDNS configuration template ([\#55](https://github.com/PowerDNS/pdns-ansible/pull/55)) NEW FEATURES: - Allow to disable automated restart of the service on configuration changes ([\#54](https://github.com/PowerDNS/pdns-ansible/pull/54)) ## v1.3.0 (2018-07-13) NEW FEATURES: - Add support to systemd overrides definitions ([\#53](https://github.com/PowerDNS/pdns-ansible/pull/53)) IMPROVEMENTS: - Implement stricter `pdns_config_dir` and `pdns_config['include-dir']` folders permissions ([\#53](https://github.com/PowerDNS/pdns-ansible/pull/53)) - Improved documentation ([\#52](https://github.com/PowerDNS/pdns-ansible/pull/52)) - Update the CI infrastructure to use molecule 2.14.0 ([\#51](https://github.com/PowerDNS/pdns-ansible/pull/51)) - Improved test coverage of systemd support ([\#49](https://github.com/PowerDNS/pdns-ansible/pull/49)) ## v1.2.1 (2018-04-06) BUG FIXES: - Fix the name of the PostgreSQL backend on RHEL ## v1.2.0 (2018-04-05) NEW FEATURES: - Allow to install PowerDNS debug packages ([\#47](https://github.com/PowerDNS/pdns-ansible/pull/47)) IMPROVEMENTS: - Improved test-suite ([\#47](https://github.com/PowerDNS/pdns-ansible/pull/47)) - Improved config files permissions handling ([\#45](https://github.com/PowerDNS/pdns-ansible/pull/45)) ## v1.1.0 (2017-11-25) IMPROVEMENTS: - Implement testing against multiple ansible versions with tox ([\#43](https://github.com/PowerDNS/pdns-ansible/pull/43)) BUG FIXES: - Fixed test cases and hardened file permissions ([\#42](https://github.com/PowerDNS/pdns-ansible/pull/42)) ## v1.0.0 (2017-10-27) IMPROVEMENTS: - Implement sorting of the configuration options ([\#35](https://github.com/PowerDNS/pdns-ansible/pull/35), [\#37](https://github.com/PowerDNS/pdns-ansible/pull/37)) BUG FIXES: - Fix the logic handling the different packages versions for Debian and CentOS ([\#43](https://github.com/PowerDNS/pdns-ansible/pull/43)) - Fix a few typos in the README file ([\#39](https://github.com/PowerDNS/pdns-ansible/pull/39)) ## v0.1.1 (2017-10-10) NEW FEATURES: - Allow to pin the PowerDNS version to be installed ([\#34](https://github.com/PowerDNS/pdns-ansible/pull/34)) IMPROVEMENTS: - Add support to the PowerDNS 4.1.x release ([\#33](https://github.com/PowerDNS/pdns-ansible/pull/33)) - Fixing minor linter issues with whitespace ([\#30](https://github.com/PowerDNS/pdns-ansible/pull/30)) BUG FIXES: - Fix Ubuntu APT repositories pinning ([\#32](https://github.com/PowerDNS/pdns-ansible/pull/32)) ## v0.1.0 (2017-06-27) Initial release. NEW FEATURES: - MySQL and SQLite databases initialization - PowerDNS installation and configuration with RHEL/CentOS and Debian/Ubuntu support - Continuous testing with TravisCI IMPROVEMENTS: - Switch to the MIT License ([\#27](https://github.com/PowerDNS/pdns-ansible/pull/27)) - Overall role refactoring ([\#28](https://github.com/PowerDNS/pdns-ansible/pull/28)) ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2017 PowerDNS.COM BV Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # Ansible Role: PowerDNS Authoritative Server [![Build Status](https://github.com/PowerDNS/pdns-ansible/actions/workflows/main.yml/badge.svg)](https://github.com/PowerDNS/pdns-ansible) [![License](https://img.shields.io/badge/license-MIT%20License-brightgreen.svg)](https://opensource.org/licenses/MIT) [![Ansible Role](https://img.shields.io/badge/ansible%20role-PowerDNS.pdns-blue.svg)](https://galaxy.ansible.com/PowerDNS/pdns) [![GitHub tag](https://img.shields.io/github/tag/PowerDNS/pdns-ansible.svg)](https://github.com/PowerDNS/pdns-ansible/tags) An Ansible role created by the folks behind PowerDNS to setup the [PowerDNS Authoritative Server](https://docs.powerdns.com/authoritative/). ## Requirements An Ansible 2.15 or higher installation. ## Dependencies None. ## Role Variables Available variables are listed below, along with their default values (see `defaults/main.yml`): ```yaml pdns_install_repo: "" ``` By default, the PowerDNS Authoritative Server is installed from the software repositories configured on the target hosts. ```yaml # Install the PowerDNS Authoritative Server from the 'master' official repository - hosts: all roles: - { role: PowerDNS.pdns, pdns_install_repo: "{{ pdns_auth_powerdns_repo_master }}" } # Install the PowerDNS Authoritative Server from the '4.8.x' official repository - hosts: all roles: - { role: PowerDNS.pdns, pdns_install_repo: "{{ pdns_auth_powerdns_repo_48 }}" } # Install the PowerDNS Authoritative Server from the '4.9.x' official repository - hosts: all roles: - { role: PowerDNS.pdns, pdns_install_repo: "{{ pdns_auth_powerdns_repo_49 }}" } # Install the PowerDNS Authoritative Server from the '5.0.x' official repository - hosts: all roles: - { role: PowerDNS.pdns, pdns_install_repo: "{{ pdns_auth_powerdns_repo_50 }}" } ``` The examples above, show how to install the PowerDNS Authoritative Server from the official PowerDNS repositories (see the complete list of pre-defined repos in `vars/main.yml`). ```yaml - hosts: all vars: pdns_install_repo: name: "powerdns" # the name of the repository apt_repo_origin: "example.com" # used to pin the PowerDNS packages to the provided repository apt_version: "auth-50" # deb822 suites suffix (appended to release codename) apt_repo: "deb http://example.com/{{ ansible_distribution | lower }} {{ ansible_distribution_release | lower }}/pdns main" gpg_key: "http://example.com/MYREPOGPGPUBKEY.asc" # repository public GPG key gpg_key_id: "MYREPOGPGPUBKEYID" # to avoid to reimport the key each time the role is executed yum_repo_baseurl: "http://example.com/centos/$basearch/$releasever/pdns" yum_debug_symbols_repo_baseurl: "http://example.com/centos/$basearch/$releasever/pdns/debug" roles: - { role: PowerDNS.pdns } ``` It is also possible to install the PowerDNS Authoritative Server from custom repositories as demonstrated in the example above. **Note:** These repositories are ignored on Arch Linux When `pdns_install_repo.apt_version` is set, this role configures Debian-family repositories using `ansible.builtin.deb822_repository` on supported releases (Ubuntu `>=22.04`, Debian `>=11`). If `apt_version` is omitted, the legacy `apt_repo` string is used with `ansible.builtin.apt_repository`. ```yaml pdns_install_epel: true ``` By default, install EPEL to satisfy some PowerDNS Authoritative Server dependencies like `protobuf`. To skip the installation of EPEL set `pdns_install_epel` to `false`. ```yaml pdns_package_name: "{{ default_pdns_package_name }}" ``` The name of the PowerDNS Authoritative Server package, `pdns` on RedHat-like systems and `pdns-server` on Debian-like systems. ```yaml pdns_package_version: "" ``` Optionally, allow to set a specific version of the PowerDNS Authoritative Server package to be installed. ```yaml pdns_package_state: "present" ``` Desired package state for `pdns_package_name`. Supported values include `present`, `latest`, and `absent`. When set to `absent`, the role removes packages and skips runtime configuration tasks. ```yaml pdns_install_debug_symbols_package: false ``` Install the PowerDNS Authoritative Server debug symbols. ```yaml pdns_debug_symbols_package_name: "{{ default_pdns_debug_symbols_package_name }}" ``` The name of the PowerDNS Authoritative Server debug package to be installed when `pdns_install_debug_symbols_package` is `true`, `pdns-debuginfo` on RedHat-like systems and `pdns-server-dbg` on Debian-like systems. ```yaml pdns_debug_symbols_package_state: "{{ pdns_package_state }}" ``` Desired package state for the debug symbols package when it is managed by this role. ```yaml pdns_user: pdns pdns_group: pdns pdns_file_owner: root pdns_file_group: "{{ pdns_group }}" ``` The user and group the PowerDNS Authoritative Server process will run as.
**NOTE**: This role does not create the user or group as we assume that they've been created by the package or other roles. ```yaml pdns_service_name: "pdns" ``` Name of the PowerDNS service. ```yaml pdns_service_state: "started" pdns_service_enabled: true pdns_service_masked: false ``` Allow to specify the desired state of the PowerDNS Authoritative Server service. ```yaml pdns_disable_handlers: false ``` Disable automated service restart on configuration changes. ```yaml pdns_manage_selinux: true ``` Enable management of SELinux booleans and ports on SELinux-enabled systems. Set to `false` to skip SELinux changes entirely. ```yaml pdns_config_dir: "{{ default_pdns_config_dir }}" pdns_config_file: "pdns.conf" ``` PowerDNS Authoritative Server configuration file and directory. ```yaml pdns_config: {} ``` Dictionary containing the PowerDNS Authoritative Server configuration.
**NOTE:** The PowerDNS backends configuration and the `config-dir`, `setuid` and `setgid` directives must be configured through the `pdns_user`, `pdns_group` and `pdns_backends` role variables (see `templates/pdns.conf.j2`). For example: ```yaml pdns_config: primary: true secondary: false local-address: '192.0.2.53' local-ipv6: '2001:DB8:1::53' local-port: '5300' ``` configures PowerDNS Authoritative Server to listen incoming DNS requests on port 5300. ```yaml pdns_service_overrides: User: "{{ pdns_user }}" Group: "{{ pdns_group }}" ``` Dict with overrides for the service (systemd only). This can be used to change any systemd settings in the `[Service]` category. ```yaml pdns_backends_packages: "{{ default_pdns_backends_packages }}" pdns_backends_packages_state: "{{ pdns_package_state }}" pdns_backends: bind: config: '/dev/null' ``` Dictionary declaring all the backends you'd like to enable. You can use multiple backends of the same kind by using the `{backend}:{instance_name}` syntax. For example: ```yaml pdns_backends: 'gmysql:one': 'user': root 'host': 127.0.0.1 'password': root 'dbname': pdns 'gmysql:two': 'user': pdns_user 'host': 192.0.2.15 'password': my_password 'dbname': dns 'bind': 'config': '/etc/named/named.conf' 'hybrid': true 'dnssec-db': '{{ pdns_config_dir }}/dnssec.db' ``` By default this role starts just the bind-backend with an empty config file. `pdns_backends_packages_state` controls install/update/removal of backend packages. ```yaml pdns_config_additional_dirs: [] ``` Optional list of directories created before `pdns_config_files` are copied. Each item can be either a path string or an object with `path`, `owner`, `group`, `mode`. For example: ```yaml pdns_config_additional_dirs: - path: "{{ pdns_config['include-dir'] }}" mode: "0775" - "{{ pdns_config_dir }}/zones" - "/var/lib/powerdns/rpz" ``` ```yaml pdns_config_files: [] ``` Optional list of files copied before the service is started. Each item must define `dest` and one of `src` or `content`. `dest` can be absolute or relative to `pdns_config_dir`. Executable backend helper scripts should be shipped via this variable too (for example with `mode: "0750"`). For example: ```yaml pdns_config_files: - src: files/pdns/named.conf dest: named.conf mode: "0640" - dest: pipe-backend.py mode: "0750" content: | #!/usr/bin/env python3 print("example") ``` ```yaml pdns_mysql_manage_database: true pdns_mysql_databases_credentials: {} pdns_mysql_query_use_socket: false pdns_mysql_unix_socket: "/var/run/mysqld/mysqld.sock" pdns_backends_mysql_cmd: "{{ default_pdns_backends_mysql_cmd }}" pdns_mysql_cli_extra_args: "{{ default_pdns_mysql_cli_extra_args }}" pdns_mysql_auth_plugin: "" pdns_mysql_user_update_password: "" pdns_mysql_packages: "{{ default_pdns_mysql_packages }}" pdns_mysql_packages_state: "present" ``` `pdns_mysql_manage_database` controls whether this role performs MySQL/MariaDB bootstrap operations (database creation, user/grants management and schema checks/import). Set it to `false` for config-only mode. Administrative credentials for the MySQL backend used to create the PowerDNS Authoritative Server databases and users. For example: ```yaml pdns_mysql_databases_credentials: 'gmysql:one': 'priv_user': root 'priv_password': my_first_password 'priv_host': - "localhost" - "%" 'gmysql:two': 'priv_user': someprivuser 'priv_password': my_second_password 'priv_host': - "localhost" ``` Notice that this must only contain the credentials for the `gmysql` backends provided in `pdns_backends`. When `pdns_mysql_query_use_socket` is set to `true`, role-internal MySQL operations (database/user creation and schema load checks/import) use the UNIX socket path defined by `pdns_mysql_unix_socket` instead of TCP host/port. `pdns_backends_mysql_cmd` and `pdns_mysql_cli_extra_args` control the MySQL/MariaDB CLI invocation used for schema checks/import. `pdns_mysql_packages` allows overriding OS-specific MySQL dependency package lists. `pdns_mysql_packages_state` controls install/update/removal of those dependency packages. ```yaml pdns_pgsql_manage_database: true pdns_pgsql_databases_credentials: {} pdns_pgsql_packages: "{{ default_pdns_pgsql_packages }}" pdns_pgsql_packages_state: "present" ``` `pdns_pgsql_manage_database` controls whether this role performs PostgreSQL bootstrap operations (database/user creation and schema checks/import). Set it to `false` for config-only mode. Administrative credentials for the PostgreSQL backend used to create the PowerDNS Authoritative Server databases and users. For example: ```yaml pdns_pgsql_databases_credentials: 'gpgsql:one': priv_user: postgres priv_password: my_first_password ``` Notice that this must only contain the credentials for the `gpgsql` backends provided in `pdns_backends`. ```yaml pdns_pgsql_query_use_socket: false pdns_pgsql_unix_socket: "/var/run/postgresql" ``` When `pdns_pgsql_query_use_socket` is set to `true`, role-internal PostgreSQL operations (database/user creation and schema load checks/import) use the UNIX socket path defined by `pdns_pgsql_unix_socket` instead of TCP host/port. `pdns_pgsql_packages` allows overriding OS-specific PostgreSQL dependency package lists. `pdns_pgsql_packages_state` controls install/update/removal of those dependency packages. ```yaml pdns_sqlite_databases_locations: [] ``` Locations of the SQLite3 databases that have to be created if using the `gsqlite3` backend. ```yaml pdns_sqlite_package_state: "present" ``` Desired package state for the SQLite CLI dependency used during schema bootstrap. ```yaml pdns_lmdb_databases_locations: [] ``` Locations of the LMDB databases that have to be created if using the `lmdb` backend. Locations of the mysql, pgsql and sqlite3 base schema. When set, this value is used and they are not automatically detected. ```yaml pdns_mysql_schema_load: true pdns_mysql_schema_file: '' pdns_mysql_schema_on_first_node_only: true pdns_pgsql_schema_load: true pdns_pgsql_schema_file: '' pdns_pgsql_schema_on_first_node_only: true pdns_sqlite_schema_file: '' ``` `pdns_mysql_schema_load` and `pdns_pgsql_schema_load` only control schema check/import tasks. When SQL bootstrap is enabled (`pdns_mysql_manage_database` / `pdns_pgsql_manage_database`) and administrative credentials are provided, user/database creation still runs even if schema load is disabled. `pdns_mysql_schema_on_first_node_only` and `pdns_pgsql_schema_on_first_node_only` control cluster bootstrap execution for shared SQL backends (database/user/grants/schema import). ```yaml pdns_verbose: "{{ ansible_verbosity | int >= 2 }}" ``` Enable verbose/debug role behavior. This currently controls whether sensitive SQL task details are hidden in logs (`false`) or visible for troubleshooting (`true`). ## Role Tags This role uses the following standard tags so filtered runs stay predictable with `--tags` / `--skip-tags`: - `install`: package/module installation or software provisioning. - `config`: configuration/state changes (templates, files, directories, settings, data bootstrap). - `service`: service state management and service-related handlers. - `repository`: repository/key/pinning setup and repository cache refresh. Some prerequisite tasks intentionally have multiple tags (for example `install` + `repository`, or `install` + `config`) so filtered runs include the dependencies required by the selected path. ## Example Playbooks Run as a primary using the bind backend (when you already have a `named.conf` file): ```yaml - hosts: ns1.example.net roles: - { role: PowerDNS.pdns } vars: pdns_config: primary: true local-address: '192.0.2.53' pdns_backends: bind: config: '/etc/named/named.conf' ``` Install the latest '50' build of PowerDNS Authoritative Server enabling the MySQL backend. Provides also the MySQL administrative credentials to automatically create and initialize the PowerDNS Authoritative Server user and database: ```yaml - hosts: ns2.example.net roles: - { role: PowerDNS.pdns } vars: pdns_config: primary: true secondary: false local-address: '192.0.2.77' pdns_backends: gmysql: host: 192.0.2.120 port: 3306 user: powerdns password: P0w3rDn5 dbname: pdns pdns_mysql_databases_credentials: gmysql: priv_user: root priv_password: myrootpass priv_host: - "%" pdns_install_repo: "{{ pdns_auth_powerdns_repo_50 }}" ``` **NOTE:** In this case the role will use the credentials provided in `pdns_mysql_databases_credentials` to automatically create and initialize the user (`user`, `password`) and database (`dbname`) connecting to the MySQL server (`host`, `port`). Configure PowerDNS Authoritative Server in 'primary' mode reading zones from two different PostgreSQL databases: ```yaml - hosts: ns2.example.net roles: - { role: PowerDNS.pdns } vars: pdns_config: primary: true local-port: 5300 local-address: '192.0.2.111' pdns_backends: 'gpgsql:serverone': host: 192.0.2.124 user: powerdns password: P0w3rDn5 dbname: pdns2 'gpgsql:otherserver': host: 192.0.2.125 user: root password: root dbname: dns ``` Configure PowerDNS Authoritative Server to run with the `gsqlite3` backend. The SQLite database will be created and initialized by the role in the location specified by the `database_name` variable. ```yaml - hosts: ns4.example.net roles: - { role: PowerDNS.pdns } vars: database_name: '/var/lib/powerdns/pdns.sqlite3' pdns_config: primary: true secondary: false local-address: '192.0.2.73' pdns_backends: gsqlite3: database: "{{ database_name }}" dnssec: true pdns_sqlite_databases_locations: - "{{ database_name }}" ``` ## Changelog A detailed changelog of all the changes applied to the role is available [here](./CHANGELOG.md). ## Testing Tests are performed by [Molecule](http://molecule.readthedocs.org/en/latest/). $ pip install tox To test all the scenarios run $ tox To run a custom molecule command $ tox -e ansible216 -- molecule test -s pdns-50 The Molecule backend matrix validates LMDB, SQLite3, MySQL, MariaDB, BIND and PostgreSQL instance profiles. ## License MIT ================================================ FILE: defaults/main.yml ================================================ --- # By default, no PowerDNS Authoritative Server repository will be configured by the role pdns_install_repo: "" # To install the PowerDNS Authoritative Server from the 'master' official repository # use the following playbook snippet # - hosts: all # roles: # - { role: PowerDNS.pdns, # pdns_install_repo: "{{ pdns_auth_powerdns_repo_master }}" } # # To install the PowerDNS Authoritative Server from the '4.8.x' official repository # use the following playbook snippet # - hosts: all # roles: # - { role: PowerDNS.pdns, # pdns_install_repo: "{{ pdns_auth_powerdns_repo_48 }}" } # To install the PowerDNS Authoritative Server from the '4.9.x' official repository # use the following playbook snippet # - hosts: all # roles: # - { role: PowerDNS.pdns, # pdns_install_repo: "{{ pdns_auth_powerdns_repo_49 }}" } # To install the PowerDNS Authoritative Server from the '5.0.x' official repository # use the following playbook snippet # - hosts: all # roles: # - { role: PowerDNS.pdns, # pdns_install_repo: "{{ pdns_auth_powerdns_repo_50 }}" } # # To make this role configure a custom repository and install the # PowerDNS Authoritative Server from it override the `pdns_install_repo` variable # as follows # - hosts: all # vars: # pdns_install_repo: # apt_repo_origin: "example.com" # Pin the PowerDNS packages to the provided repository origin # apt_version: "auth-50" # Deb822 suite suffix (appended to release codename, Ubuntu >=22.04 / Debian >=11) # apt_repo: "deb http://example.com/{{ ansible_distribution | lower }} {{ ansible_distribution_release | lower }}/pdns main" # gpg_key: "http://example.com/MYREPOGPGPUBKEY.asc" # repository public GPG key # gpg_key_id: "MYREPOGPGPUBKEYID" # to avoid to reimport the key each time the role is executed # yum_repo_baseurl: "http://example.com/centos/$basearch/$releasever/pdns" # name: "powerdns" # the name of the repository # roles: # - { role: PowerDNS.pdns } # Install the EPEL repository. # EPEL is needed to satisfy some PowerDNS Authoritative Server dependencies like protobuf pdns_install_epel: true # The name of the PowerDNS Authoritative Server package pdns_package_name: "{{ default_pdns_package_name }}" # Install a specific version of the PowerDNS Authoritative Server package # NB: The usage of this variable makes only sense on RedHat-like systems, # where each YUM repository can contains multiple versions of the same package. pdns_package_version: "" # Desired state of the PowerDNS Authoritative Server package. # Supported values include present, latest and absent. pdns_package_state: "present" # Install the PowerDNS Authoritative Server debug symbols package pdns_install_debug_symbols_package: false # The name of the PowerDNS Authoritative Server debug symbols package pdns_debug_symbols_package_name: "{{ default_pdns_debug_symbols_package_name }}" # Desired state of the debug symbols package when managed by this role. # Supported values include present, latest and absent. pdns_debug_symbols_package_state: "{{ pdns_package_state }}" # The user and group the PowerDNS Authoritative Server process will run as. # NOTE: at the moment, we don't create a user as we assume the package creates # a "pdns" user and group. If you change these variables, make sure to create # the user and groups before applying this role pdns_user: "pdns" pdns_group: "pdns" pdns_file_owner: "root" pdns_file_group: "{{ pdns_group }}" # Name of the PowerDNS Authoritative Server Service pdns_service_name: "pdns" # State of the PowerDNS Authoritative Server service pdns_service_state: "started" pdns_service_enabled: true pdns_service_masked: false # When True, disable the automated restart of the PowerDNS service pdns_disable_handlers: false # When true, manage SELinux booleans and ports on SELinux-enabled systems. pdns_manage_selinux: true # PowerDNS Authoritative Server configuration file and directory pdns_config_dir: "{{ default_pdns_config_dir }}" pdns_config_file: "pdns.conf" # Dict containing all configuration options, except for backend # configuration and the "config-dir", "setuid" and "setgid" directives. pdns_config: {} # pdns_config: # primary: true # secondary: false # local-address: '192.0.2.53' # local-ipv6: '2001:DB8:1::53' # local-port: '5300' # Dict with overrides for the service (systemd only) pdns_service_overrides: "{{ default_pdns_service_overrides }}" # pdns_service_overrides: # LimitNOFILE: 10000 # Dictionary of packages that should be installed to enable the backends. # backendname: packagename pdns_backends_packages: "{{ default_pdns_backends_packages }}" # Desired state of backend packages. # Supported values include present, latest and absent. pdns_backends_packages_state: "{{ pdns_package_state }}" # A dict with all the backends you'd like to configure. # This default starts just the bind-backend with an empty config file pdns_backends: bind: config: '/dev/null' # pdns_backends: # 'gmysql:one': # 'user': root # 'host': 127.0.0.1 # 'password': root # 'dbname': pdns # 'gmysql:two': # 'user': pdns_user # 'host': 192.0.2.15 # 'port': 3307 # 'password': my_password # 'dbname': dns # 'bind': # 'config': '/etc/named/named.conf' # 'hybrid': true # 'check-interval': 60 # 'dnssec-db': '{{ pdns_config_dir }}/dnssec.db' # Additional directories to create before writing pdns_config_files. # Each item can be: # - a string path # - or a dict with path/owner/group/mode # # Examples: # pdns_config_additional_dirs: # - path: "{{ pdns_config['include-dir'] }}" # mode: "0775" # - "{{ pdns_config_dir }}/zones" # - "/var/lib/powerdns/rpz" pdns_config_additional_dirs: [] # Files to copy into the PowerDNS configuration directory. # Each item supports: # - src: path on the controller # - content: inline file content # - dest: destination path (absolute, or relative to pdns_config_dir) # - owner/group/mode: optional file attributes # - dir_owner/dir_group/dir_mode: optional parent directory attributes # # Examples: # pdns_config_files: # - src: files/pdns/my-named.conf # dest: named.conf # mode: "0640" # - dest: pipe-backend.py # mode: "0750" # content: | # #!/usr/bin/env python3 # print("backend") pdns_config_files: [] # Enable role-managed MySQL backend bootstrap tasks. # When false, the role will only write gmysql backend settings in pdns.conf and won't connect to MySQL/MariaDB. pdns_mysql_manage_database: true # Administrative credentials to create the PowerDNS Authoritative Server MySQL backend database and user. pdns_mysql_databases_credentials: {} # pdns_mysql_databases_credentials: # 'gmysql:one': # 'priv_user': root # 'priv_password': my_first_password # 'priv_host': # - "localhost" # - "%" # 'gmysql:two': # 'priv_user': someprivuser # 'priv_password': my_second_password # 'priv_host': # - "localhost" # Use a UNIX socket for role-internal MySQL operations (db create, grants, schema checks/import). pdns_mysql_query_use_socket: false # Packages needed to install MySQL dependencies. # By default, OS-specific vars files provide the actual package list. pdns_mysql_packages: "{{ default_pdns_mysql_packages }}" # Desired state of MySQL dependency packages. # Supported values include present, latest and absent. pdns_mysql_packages_state: "{{ pdns_package_state }}" # UNIX socket path used when pdns_mysql_query_use_socket is true. pdns_mysql_unix_socket: "/var/run/mysqld/mysqld.sock" # MySQL/MariaDB CLI command used for schema checks/import. pdns_backends_mysql_cmd: "{{ default_pdns_backends_mysql_cmd }}" # Additional arguments appended to the MySQL/MariaDB CLI command used for schema checks/import. pdns_mysql_cli_extra_args: "{{ default_pdns_mysql_cli_extra_args }}" # Authentication plugin used for created/granted MySQL users. # Keep empty to let the module use legacy password flow (mysql_native_password path). # Set to caching_sha2_password for MySQL 8.4/9+ servers where mysql_native_password is unavailable. pdns_mysql_auth_plugin: "" # Password update strategy for mysql_user task. # Accepted values: always, on_create, on_new_username. # Keep empty for role defaults: # - on_create when pdns_mysql_auth_plugin is set # - always when pdns_mysql_auth_plugin is empty pdns_mysql_user_update_password: "" # Enable role-managed PostgreSQL backend bootstrap tasks. # When false, the role will only write gpgsql backend settings in pdns.conf and won't connect to PostgreSQL. pdns_pgsql_manage_database: true # Administrative credentials to create the PowerDNS Authoritative Server PostgreSQL backend database and user. pdns_pgsql_databases_credentials: {} # pdns_pgsql_databases_credentials: # gpgsql: # priv_user: postgres # priv_password: my_privileged_password # Use a UNIX socket for role-internal PostgreSQL operations (db create, schema checks/import). pdns_pgsql_query_use_socket: false # Packages needed to install PostgreSQL dependencies. # By default, OS-specific vars files provide the actual package list. pdns_pgsql_packages: "{{ default_pdns_pgsql_packages }}" # Desired state of PostgreSQL dependency packages. # Supported values include present, latest and absent. pdns_pgsql_packages_state: "{{ pdns_package_state }}" # UNIX socket path used when pdns_pgsql_query_use_socket is true. pdns_pgsql_unix_socket: "/var/run/postgresql" # This will create the PowerDNS Authoritative Server backend SQLite database # in the given locations. # NOTE: Requires the SQLite CLI tools to be available in the machine and the gsqlite3 # backend to be installed on the machine. pdns_sqlite_databases_locations: [] # Desired state of the SQLite CLI dependency package. # Supported values include present, latest and absent. pdns_sqlite_package_state: "{{ pdns_package_state }}" # This will create the PowerDNS Authoritative Server backend LMDB database # in the given locations. # NOTE: Requires lmdb backend to be installed on the machine. pdns_lmdb_databases_locations: [] # By default, we'll load the MySQL default schema. Set this to false to disable loading the schema # (e.g. when importing your own dump later on). # NOTE: This controls only schema check/import. User/database creation and grants are still executed # when pdns_mysql_manage_database is true and administrative credentials are provided. pdns_mysql_schema_load: true # Override the schema used to initialize the MySQL database # By default, this role tries to detect the correct file pdns_mysql_schema_file: "" # Run MySQL backend bootstrap tasks only on first node? # This includes database creation, grants and schema import. # This should be used if you install pdns on a cluster pdns_mysql_schema_on_first_node_only: true # By default, we'll load the PostgreSQL default schema. Set this to false to disable loading the schema # (e.g. when importing your own dump later on). # NOTE: This controls only schema check/import. User/database creation is still executed # when pdns_pgsql_manage_database is true and administrative credentials are provided. pdns_pgsql_schema_load: true # Override the schema used to initialize the PostgreSQL database # By default, this role tries to detect the correct file pdns_pgsql_schema_file: "" # Run pgsql backend bootstrap tasks only on first node? # This includes database/user creation and schema import. # This should be used if you install pdns on a cluster pdns_pgsql_schema_on_first_node_only: true # Override the schema used to initialize the SQLite database # By default, this role tries to detect the correct file pdns_sqlite_schema_file: "" # Set debug mode flag from Ansible verbosity pdns_verbose: "{{ ansible_verbosity | int >= 2 }}" ================================================ FILE: handlers/main.yml ================================================ --- - name: Reload systemd ansible.builtin.systemd: daemon_reload: true listen: reload systemd when: not pdns_disable_handlers tags: - service - name: Restart PowerDNS ansible.builtin.systemd: name: "{{ pdns_service_name }}" state: restarted listen: restart pdns when: - not pdns_disable_handlers - pdns_service_state != 'stopped' tags: - service - name: Update the apt cache ansible.builtin.apt: update_cache: true listen: update the apt cache tags: - install - repository ================================================ FILE: meta/main.yml ================================================ --- galaxy_info: role_name: "pdns" namespace: "powerdns" author: PowerDNS Engineering Team description: Install and configure the PowerDNS Authoritative DNS Server company: PowerDNS.COM BV license: MIT min_ansible_version: "2.15" platforms: - name: EL versions: - "8" - "9" - "10" - name: Debian versions: - bullseye - bookworm - trixie - name: Ubuntu versions: - focal - jammy - noble - name: ArchLinux galaxy_tags: - system - dns - pdns - powerdns - auth ================================================ FILE: molecule/pdns-48/converge.yml ================================================ --- - name: PowerDNS 4.8.x LMDB default instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-48.yml - ../resources/vars/pdns-backend-lmdb.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_lmdb | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the LMDB instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the LMDB instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the LMDB instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the LMDB instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 4.8.x SQLite instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-48.yml - ../resources/vars/pdns-backend-sqlite3.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_sqlite3 | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the SQLite instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the SQLite instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the SQLite instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the SQLite instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 4.8.x MySQL instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-48.yml - ../resources/vars/pdns-backend-mysql.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_mysql | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the MySQL instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the MySQL instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the MySQL instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the MySQL instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 4.8.x MariaDB instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-48.yml - ../resources/vars/pdns-backend-mariadb.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_mariadb | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the MariaDB instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the MariaDB instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the MariaDB instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the MariaDB instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 4.8.x Bind instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-48.yml - ../resources/vars/pdns-backend-bind.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_bind | default({}), recursive=true) }} roles: - { role: powerdns.pdns } - name: PowerDNS 4.8.x PostgreSQL instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-48.yml - ../resources/vars/pdns-backend-postgresql.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_pgsql | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the PostgreSQL instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the PostgreSQL instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the PostgreSQL instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the PostgreSQL instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 4.8.x Hide default service hosts: pdns vars: pdns_service_state: "stopped" pdns_service_enabled: "no" pdns_service_masked: true roles: - { role: powerdns.pdns } ================================================ FILE: molecule/pdns-48/molecule.yml ================================================ --- scenario: name: pdns-48 driver: name: docker dependency: name: galaxy platforms: - name: rockylinux-8 groups: ["pdns"] image: rockylinux:8 dockerfile_tpl: el-systemd - name: rockylinux-9 groups: ["pdns"] image: rockylinux:9 dockerfile_tpl: el-systemd - name: almalinux-8 groups: ["pdns"] image: almalinux:8 dockerfile_tpl: el-systemd - name: almalinux-9 groups: ["pdns"] image: almalinux:9 dockerfile_tpl: el-systemd - name: oraclelinux-8 groups: ["pdns"] image: oraclelinux:8 dockerfile_tpl: el-systemd - name: oraclelinux-9 groups: ["pdns"] image: oraclelinux:9 dockerfile_tpl: el-systemd - name: ubuntu-2204 groups: ["pdns"] image: ubuntu:22.04 dockerfile_tpl: debian-systemd - name: debian-11 groups: ["pdns"] image: debian:11 dockerfile_tpl: debian-systemd - name: debian-12 groups: ["pdns"] image: debian:12 dockerfile_tpl: debian-systemd # In order to run the tests we need # a MySQL container to be up & running - name: mysql image: mysql:8.4.8 env: MYSQL_ROOT_PASSWORD: pdns MYSQL_ROOT_HOST: '%' # Declaring the container as service, # will link it to the others Platforms containers # on creation. is_service: true # Additional service for gmysql tests against MariaDB 10.6 - name: mariadb image: mariadb:10.6 env: MARIADB_ROOT_PASSWORD: pdns MARIADB_ROOT_HOST: '%' is_service: true # PostgreSQL service for gpgsql backend tests - name: postgresql image: postgres:16 env: POSTGRES_PASSWORD: pdns is_service: true provisioner: name: ansible options: diff: true v: true config_options: defaults: gathering: smart fact_caching: jsonfile fact_caching_connection: .ansible_cache fact_caching_timeout: 7200 ssh_connection: pipelining: true playbooks: # cleanup: ../resources/cleanup.yml create: ../resources/create.yml destroy: ../resources/destroy.yml prepare: ../resources/prepare.yml lint: ansible-lint lint: yamllint defaults tasks meta vars verifier: name: testinfra options: hosts: "pdns" vvv: true directory: ../resources/tests/all additional_files_or_dirs: # path relative to 'directory' - ../repo-48/ - ../backend-sqlite/ - ../backend-lmdb/ - ../backend-mysql/ - ../backend-mariadb/ - ../backend-postgresql/ - ../backend-bind/ - ../backend-zones/ - ../service-mask/ - ../systemd-override/ ================================================ FILE: molecule/pdns-49/converge.yml ================================================ --- - name: PowerDNS 4.9.x LMDB default instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-49.yml - ../resources/vars/pdns-backend-lmdb.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_lmdb | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the LMDB instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the LMDB instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the LMDB instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the LMDB instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 4.9.x SQLite instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-49.yml - ../resources/vars/pdns-backend-sqlite3.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_sqlite3 | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the SQLite instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the SQLite instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the SQLite instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the SQLite instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 4.9.x MySQL instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-49.yml - ../resources/vars/pdns-backend-mysql.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_mysql | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the MySQL instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the MySQL instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the MySQL instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the MySQL instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 4.9.x MariaDB instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-49.yml - ../resources/vars/pdns-backend-mariadb.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_mariadb | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the MariaDB instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the MariaDB instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the MariaDB instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the MariaDB instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 4.9.x Bind instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-49.yml - ../resources/vars/pdns-backend-bind.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_bind | default({}), recursive=true) }} roles: - { role: powerdns.pdns } - name: PowerDNS 4.9.x PostgreSQL instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-49.yml - ../resources/vars/pdns-backend-postgresql.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_pgsql | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the PostgreSQL instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the PostgreSQL instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the PostgreSQL instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the PostgreSQL instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 4.9.x Hide default service hosts: pdns vars: pdns_service_state: "stopped" pdns_service_enabled: "no" pdns_service_masked: true roles: - { role: powerdns.pdns } ================================================ FILE: molecule/pdns-49/molecule.yml ================================================ --- scenario: name: pdns-49 driver: name: docker dependency: name: galaxy platforms: - name: rockylinux-8 groups: ["pdns"] image: rockylinux:8 dockerfile_tpl: el-systemd - name: rockylinux-9 groups: ["pdns"] image: rockylinux:9 dockerfile_tpl: el-systemd - name: almalinux-8 groups: ["pdns"] image: almalinux:8 dockerfile_tpl: el-systemd - name: almalinux-9 groups: ["pdns"] image: almalinux:9 dockerfile_tpl: el-systemd - name: oraclelinux-8 groups: ["pdns"] image: oraclelinux:8 dockerfile_tpl: el-systemd - name: oraclelinux-9 groups: ["pdns"] image: oraclelinux:9 dockerfile_tpl: el-systemd - name: ubuntu-2204 groups: ["pdns"] image: ubuntu:22.04 dockerfile_tpl: debian-systemd - name: ubuntu-2404 groups: ["pdns"] image: ubuntu:24.04 dockerfile_tpl: debian-systemd - name: debian-11 groups: ["pdns"] image: debian:11 dockerfile_tpl: debian-systemd - name: debian-12 groups: ["pdns"] image: debian:12 dockerfile_tpl: debian-systemd - name: debian-13 groups: ["pdns"] image: debian:13 dockerfile_tpl: debian-systemd # In order to run the tests we need # a MySQL container to be up & running - name: mysql image: mysql:8.4.8 env: MYSQL_ROOT_PASSWORD: pdns MYSQL_ROOT_HOST: '%' # Declaring the container as service, # will link it to the others Platforms containers # on creation. is_service: true # Additional service for gmysql tests against MariaDB 10.6 - name: mariadb image: mariadb:10.6 env: MARIADB_ROOT_PASSWORD: pdns MARIADB_ROOT_HOST: '%' is_service: true # PostgreSQL service for gpgsql backend tests - name: postgresql image: postgres:16 env: POSTGRES_PASSWORD: pdns is_service: true provisioner: name: ansible options: diff: true v: true config_options: defaults: gathering: smart fact_caching: jsonfile fact_caching_connection: .ansible_cache fact_caching_timeout: 7200 ssh_connection: pipelining: true playbooks: # cleanup: ../resources/cleanup.yml create: ../resources/create.yml destroy: ../resources/destroy.yml prepare: ../resources/prepare.yml lint: ansible-lint lint: yamllint defaults tasks meta vars verifier: name: testinfra options: hosts: "pdns" vvv: true directory: ../resources/tests/all additional_files_or_dirs: # path relative to 'directory' - ../repo-49/ - ../backend-sqlite/ - ../backend-lmdb/ - ../backend-mysql/ - ../backend-mariadb/ - ../backend-postgresql/ - ../backend-bind/ - ../backend-zones/ - ../service-mask/ - ../systemd-override/ ================================================ FILE: molecule/pdns-50/converge.yml ================================================ --- - name: PowerDNS 5.0.x LMDB default instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-50.yml - ../resources/vars/pdns-backend-lmdb.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_lmdb | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the LMDB instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: pdns changed_when: false failed_when: false - name: Provision the LMDB instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: pdns changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the LMDB instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the LMDB instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 5.0.x SQLite instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-50.yml - ../resources/vars/pdns-backend-sqlite3.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_sqlite3 | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the SQLite instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: pdns changed_when: false failed_when: false - name: Provision the SQLite instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: pdns changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the SQLite instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the SQLite instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 5.0.x MySQL instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-50.yml - ../resources/vars/pdns-backend-mysql.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_mysql | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the MySQL instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: pdns changed_when: false failed_when: false - name: Provision the MySQL instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: pdns changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the MySQL instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the MySQL instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 5.0.x MariaDB instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-50.yml - ../resources/vars/pdns-backend-mariadb.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_mariadb | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the MariaDB instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: pdns changed_when: false failed_when: false - name: Provision the MariaDB instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: pdns changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the MariaDB instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the MariaDB instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 5.0.x Bind instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-50.yml - ../resources/vars/pdns-backend-bind.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_bind | default({}), recursive=true) }} roles: - { role: powerdns.pdns } - name: PowerDNS 5.0.x PostgreSQL instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-50.yml - ../resources/vars/pdns-backend-postgresql.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_pgsql | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the PostgreSQL instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: pdns changed_when: false failed_when: false - name: Provision the PostgreSQL instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: pdns changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the PostgreSQL instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the PostgreSQL instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS 5.0.x Hide default service hosts: pdns vars: pdns_service_state: "stopped" pdns_service_enabled: "no" pdns_service_masked: true roles: - { role: powerdns.pdns } ================================================ FILE: molecule/pdns-50/molecule.yml ================================================ --- scenario: name: pdns-50 driver: name: docker dependency: name: galaxy platforms: - name: rockylinux-8 groups: ["pdns"] image: rockylinux:8 dockerfile_tpl: el-systemd - name: rockylinux-9 groups: ["pdns"] image: rockylinux:9 dockerfile_tpl: el-systemd - name: almalinux-8 groups: ["pdns"] image: almalinux:8 dockerfile_tpl: el-systemd - name: almalinux-9 groups: ["pdns"] image: almalinux:9 dockerfile_tpl: el-systemd - name: almalinux-10 groups: ["pdns"] image: almalinux:10 dockerfile_tpl: el-systemd - name: oraclelinux-8 groups: ["pdns"] image: oraclelinux:8 dockerfile_tpl: el-systemd - name: oraclelinux-9 groups: ["pdns"] image: oraclelinux:9 dockerfile_tpl: el-systemd - name: oraclelinux-10 groups: ["pdns"] image: oraclelinux:10 dockerfile_tpl: el-systemd - name: ubuntu-2204 groups: ["pdns"] image: ubuntu:22.04 dockerfile_tpl: debian-systemd - name: ubuntu-2404 groups: ["pdns"] image: ubuntu:24.04 dockerfile_tpl: debian-systemd - name: debian-11 groups: ["pdns"] image: debian:11 dockerfile_tpl: debian-systemd - name: debian-12 groups: ["pdns"] image: debian:12 dockerfile_tpl: debian-systemd - name: debian-13 groups: ["pdns"] image: debian:13 dockerfile_tpl: debian-systemd # In order to run the tests we need # a MySQL container to be up & running - name: mysql image: mysql:8.4.8 env: MYSQL_ROOT_PASSWORD: pdns MYSQL_ROOT_HOST: '%' # Declaring the container as service, # will link it to the others containers on creation is_service: true # Additional service for gmysql tests against MariaDB 10.6 - name: mariadb image: mariadb:10.6 env: MARIADB_ROOT_PASSWORD: pdns MARIADB_ROOT_HOST: '%' is_service: true # PostgreSQL service for gpgsql backend tests - name: postgresql image: postgres:16 env: POSTGRES_PASSWORD: pdns is_service: true provisioner: name: ansible options: diff: true v: true config_options: defaults: gathering: smart fact_caching: jsonfile fact_caching_connection: .ansible_cache fact_caching_timeout: 7200 ssh_connection: pipelining: true playbooks: # cleanup: ../resources/cleanup.yml create: ../resources/create.yml destroy: ../resources/destroy.yml prepare: ../resources/prepare.yml lint: ansible-lint lint: yamllint defaults handlers tasks meta vars verifier: name: testinfra options: hosts: "pdns" v: true directory: ../resources/tests/all additional_files_or_dirs: # path relative to 'directory' - ../repo-50/ - ../backend-sqlite/ - ../backend-lmdb/ - ../backend-mysql/ - ../backend-mariadb/ - ../backend-postgresql/ - ../backend-bind/ - ../backend-zones/ - ../service-mask/ - ../systemd-override/ ================================================ FILE: molecule/pdns-master/converge.yml ================================================ --- - name: PowerDNS Master LMDB default instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-master.yml - ../resources/vars/pdns-backend-lmdb.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_lmdb | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the LMDB instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the LMDB instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the LMDB instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the LMDB instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS Master SQLite instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-master.yml - ../resources/vars/pdns-backend-sqlite3.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_sqlite3 | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the SQLite instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the SQLite instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the SQLite instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the SQLite instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS Master MySQL instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-master.yml - ../resources/vars/pdns-backend-mysql.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_mysql | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the MySQL instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the MySQL instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the MySQL instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the MySQL instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS Master MariaDB instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-master.yml - ../resources/vars/pdns-backend-mariadb.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_mariadb | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the MariaDB instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the MariaDB instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the MariaDB instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the MariaDB instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS Master Bind instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-master.yml - ../resources/vars/pdns-backend-bind.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_bind | default({}), recursive=true) }} roles: - { role: powerdns.pdns } - name: PowerDNS Master PostgreSQL instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-repo-master.yml - ../resources/vars/pdns-backend-postgresql.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_pgsql | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the PostgreSQL instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the PostgreSQL instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the PostgreSQL instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the PostgreSQL instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS Master Hide default service hosts: pdns vars: pdns_service_state: "stopped" pdns_service_enabled: "no" pdns_service_masked: true roles: - { role: powerdns.pdns } ================================================ FILE: molecule/pdns-master/molecule.yml ================================================ --- scenario: name: pdns-master driver: name: docker dependency: name: galaxy platforms: - name: rockylinux-8 groups: ["pdns"] image: rockylinux:8 dockerfile_tpl: el-systemd - name: rockylinux-9 groups: ["pdns"] image: rockylinux:9 dockerfile_tpl: el-systemd - name: almalinux-8 groups: ["pdns"] image: almalinux:8 dockerfile_tpl: el-systemd - name: almalinux-9 groups: ["pdns"] image: almalinux:9 dockerfile_tpl: el-systemd - name: oraclelinux-8 groups: ["pdns"] image: oraclelinux:8 dockerfile_tpl: el-systemd - name: oraclelinux-9 groups: ["pdns"] image: oraclelinux:9 dockerfile_tpl: el-systemd - name: ubuntu-2204 groups: ["pdns"] image: ubuntu:22.04 dockerfile_tpl: debian-systemd - name: ubuntu-2404 groups: ["pdns"] image: ubuntu:24.04 dockerfile_tpl: debian-systemd - name: debian-11 groups: ["pdns"] image: debian:11 dockerfile_tpl: debian-systemd - name: debian-12 groups: ["pdns"] image: debian:12 dockerfile_tpl: debian-systemd # In order to run the tests we need # a MySQL container to be up & running - name: mysql image: mysql:8.4.8 env: MYSQL_ROOT_PASSWORD: pdns MYSQL_ROOT_HOST: '%' # Declaring the container as service, # will link it to the others Platforms containers # on creation. is_service: true # Additional service for gmysql tests against MariaDB 10.6 - name: mariadb image: mariadb:10.6 env: MARIADB_ROOT_PASSWORD: pdns MARIADB_ROOT_HOST: '%' is_service: true # PostgreSQL service for gpgsql backend tests - name: postgresql image: postgres:16 env: POSTGRES_PASSWORD: pdns is_service: true provisioner: name: ansible options: diff: true v: true config_options: defaults: gathering: smart fact_caching: jsonfile fact_caching_connection: .ansible_cache fact_caching_timeout: 7200 ssh_connection: pipelining: true playbooks: # cleanup: ../resources/cleanup.yml create: ../resources/create.yml destroy: ../resources/destroy.yml prepare: ../resources/prepare.yml lint: ansible-lint lint: yamllint defaults tasks meta vars verifier: name: testinfra options: hosts: "pdns" vvv: true directory: ../resources/tests/all additional_files_or_dirs: # path relative to 'directory' - ../repo-master/ - ../backend-sqlite/ - ../backend-lmdb/ - ../backend-mysql/ - ../backend-mariadb/ - ../backend-postgresql/ - ../backend-bind/ - ../backend-zones/ - ../service-mask/ - ../systemd-override/ ================================================ FILE: molecule/pdns-os-repos/converge.yml ================================================ --- - name: PowerDNS LMDB default instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-backend-lmdb.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_lmdb | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the LMDB instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the LMDB instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the LMDB instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the LMDB instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS SQLite instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-backend-sqlite3.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_sqlite3 | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the SQLite instance zone exists ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true become_user: "{{ pdns_user }}" changed_when: false failed_when: false - name: Provision the SQLite instance zone ansible.builtin.command: "pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true become_user: "{{ pdns_user }}" changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the SQLite instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the SQLite instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS MySQL instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-backend-mysql.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_mysql | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the MySQL instance zone exists ansible.builtin.command: "sudo -u powerdns -- pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true changed_when: false failed_when: false - name: Provision the MySQL instance zone ansible.builtin.command: "sudo -u powerdns -- pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the MySQL instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the MySQL instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS MariaDB instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-backend-mariadb.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_mariadb | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the MariaDB instance zone exists ansible.builtin.command: "sudo -u powerdns -- pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true changed_when: false failed_when: false - name: Provision the MariaDB instance zone ansible.builtin.command: "sudo -u powerdns -- pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the MariaDB instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the MariaDB instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS Bind instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-backend-bind.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_bind | default({}), recursive=true) }} roles: - { role: powerdns.pdns } - name: PowerDNS PostgreSQL instance hosts: pdns vars_files: - ../resources/vars/pdns-common.yml - ../resources/vars/pdns-backend-postgresql.yml vars: pdns_service_name: "{{ pdns_instance.service_name }}" pdns_service_enabled: "{{ pdns_instance.service_enabled }}" pdns_config_file: "{{ pdns_instance.config_file }}" pdns_config: >- {{ pdns_config_common | combine(pdns_instance.config_overrides | default({}), recursive=true) | combine(pdns_config_overrides_pgsql | default({}), recursive=true) }} roles: - { role: powerdns.pdns } post_tasks: - name: Check if the PostgreSQL instance zone exists ansible.builtin.command: "sudo -u powerdns -- pdnsutil --config-name={{ pdns_instance.config_name }} list-zone {{ pdns_instance.zone }}" register: _pdns_backend_zone_check become: true changed_when: false failed_when: false - name: Provision the PostgreSQL instance zone ansible.builtin.command: "sudo -u powerdns -- pdnsutil --config-name={{ pdns_instance.config_name }} create-zone {{ pdns_instance.zone }} ns1.{{ pdns_instance.zone }}" register: _pdns_backend_zone_created become: true changed_when: _pdns_backend_zone_check.rc != 0 notify: Restart the PostgreSQL instance service when: _pdns_backend_zone_check.rc != 0 handlers: - name: Restart the PostgreSQL instance service ansible.builtin.systemd: name: "{{ pdns_instance.service_name }}" state: restarted - name: PowerDNS Hide default service hosts: pdns vars: pdns_service_state: "stopped" pdns_service_enabled: "no" pdns_service_masked: true roles: - { role: powerdns.pdns } ================================================ FILE: molecule/pdns-os-repos/molecule.yml ================================================ --- scenario: name: pdns-os-repos driver: name: docker dependency: name: galaxy platforms: - name: archlinux groups: ["pdns"] image: archlinux:base dockerfile_tpl: archlinux-systemd # In order to run the tests we need # a MySQL container to be up & running - name: mysql image: mysql:8.4.8 env: MYSQL_ROOT_PASSWORD: pdns MYSQL_ROOT_HOST: '%' # Declaring the container as service, # will link it to the others containers on creation is_service: true # Additional service for gmysql tests against MariaDB 10.6 - name: mariadb image: mariadb:10.6 env: MARIADB_ROOT_PASSWORD: pdns MARIADB_ROOT_HOST: '%' is_service: true # PostgreSQL service for gpgsql backend tests - name: postgresql image: postgres:16 env: POSTGRES_PASSWORD: pdns is_service: true provisioner: name: ansible options: diff: true v: true config_options: defaults: gathering: smart fact_caching: jsonfile fact_caching_connection: .ansible_cache fact_caching_timeout: 7200 ssh_connection: pipelining: true playbooks: # cleanup: ../resources/cleanup.yml create: ../resources/create.yml destroy: ../resources/destroy.yml prepare: ../resources/prepare.yml lint: ansible-lint lint: yamllint defaults tasks meta vars verifier: name: testinfra options: hosts: "pdns" vvv: true directory: ../resources/tests/all additional_files_or_dirs: # path relative to 'directory' - ../backend-sqlite/ - ../backend-lmdb/ - ../backend-mysql/ - ../backend-mariadb/ - ../backend-postgresql/ - ../backend-bind/ - ../backend-zones/ - ../service-mask/ - ../systemd-override/ ================================================ FILE: molecule/resources/Dockerfile.archlinux-systemd.j2 ================================================ # Molecule managed {% set archlinux_base_image = 'menci/archlinuxarm:latest' if (item.name | lower == 'archlinux' and (molecule_docker_arch | default('')) == 'arm64') else item.image %} FROM {{ archlinux_base_image }} RUN pacman -Syu --noconfirm && \ pacman -S --noconfirm systemd awk bash ca-certificates geoip grep inetutils \ iproute2 libmaxminddb net-tools procps-ng python python-cryptography \ python-pip sudo vim yaml-cpp && \ rm -rf /usr/share/doc/* && \ rm -rf /usr/share/man/* && \ pacman -Scc --noconfirm RUN cd /usr/lib/systemd/system/sysinit.target.wants/; \ for i in *; do [ $i = systemd-tmpfiles-setup.service ] || rm -f $i; done RUN rm -f /usr/lib/systemd/system/multi-user.target.wants/* \ /etc/systemd/system/*.wants/* \ /usr/lib/systemd/system/local-fs.target.wants/* \ /usr/lib/systemd/system/sockets.target.wants/*udev* \ /usr/lib/systemd/system/sockets.target.wants/*initctl* \ /usr/lib/systemd/system/basic.target.wants/* \ /usr/lib/systemd/system/anaconda.target.wants/* # Disable requiretty. RUN sed -i -e 's/^\(Defaults\s*requiretty\)/#--- \1/' /etc/sudoers || echo "Defaults !requiretty" > /etc/sudoers.d/molecule # Create `ansible` user with sudo permissions ENV ANSIBLE_USER=ansible SUDO_GROUP=wheel RUN set -xe && \ groupadd -r ${ANSIBLE_USER} && \ useradd -m -g ${ANSIBLE_USER} ${ANSIBLE_USER} && \ usermod -aG ${SUDO_GROUP} ${ANSIBLE_USER} && \ sed -i "/^# %${SUDO_GROUP}/s/^# //g" /etc/sudoers && \ sed -i "/^%${SUDO_GROUP}/s/ALL$/NOPASSWD:ALL/g" /etc/sudoers VOLUME [ "/sys/fs/cgroup", "/tmp", "/run" ] CMD [ "/usr/lib/systemd/systemd" ] ================================================ FILE: molecule/resources/Dockerfile.debian-systemd.j2 ================================================ # Molecule managed FROM {{ item.image }} ENV container docker ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update -y && \ apt-get install -y --no-install-recommends systemd python3 python3-pip python3-apt sudo adduser bash net-tools iproute2 procps && \ rm -Rf /usr/share/doc && \ rm -Rf /usr/share/man && \ apt-get clean RUN rm -f /lib/systemd/system/multi-user.target.wants/* \ /etc/systemd/system/*.wants/* \ /lib/systemd/system/local-fs.target.wants/* \ /lib/systemd/system/sockets.target.wants/*udev* \ /lib/systemd/system/sockets.target.wants/*initctl* \ /lib/systemd/system/sysinit.target.wants/systemd-tmpfiles-setup* \ /lib/systemd/system/systemd-update-utmp* # Disable requiretty. RUN sed -i -e 's/^\(Defaults\s*requiretty\)/#--- \1/' /etc/sudoers # Create `ansible` user with sudo permissions ENV ANSIBLE_USER=ansible SUDO_GROUP=sudo RUN set -xe && \ groupadd -r ${ANSIBLE_USER} && \ useradd -m -g ${ANSIBLE_USER} ${ANSIBLE_USER} && \ usermod -aG ${SUDO_GROUP} ${ANSIBLE_USER} && \ sed -i "/^%${SUDO_GROUP}/s/ALL$/NOPASSWD:ALL/g" /etc/sudoers VOLUME [ "/sys/fs/cgroup", "/tmp", "/run" ] CMD [ "/lib/systemd/systemd" ] ================================================ FILE: molecule/resources/Dockerfile.el-systemd.j2 ================================================ # Molecule managed FROM {{ item.image }} ENV container docker RUN dnf makecache && \ dnf install -y systemd python3 python3-pip sudo bash vim iproute procps-ng hostname && \ rm -Rf /usr/share/doc && \ rm -Rf /usr/share/man && \ dnf clean all RUN cd /lib/systemd/system/sysinit.target.wants/; \ for i in *; do [ $i = systemd-tmpfiles-setup.service ] || rm -f $i; done RUN rm -f /lib/systemd/system/multi-user.target.wants/* \ /etc/systemd/system/*.wants/* \ /lib/systemd/system/local-fs.target.wants/* \ /lib/systemd/system/sockets.target.wants/*udev* \ /lib/systemd/system/sockets.target.wants/*initctl* \ /lib/systemd/system/basic.target.wants/* \ /lib/systemd/system/anaconda.target.wants/* # Disable requiretty. RUN sed -i -e 's/^\(Defaults\s*requiretty\)/#--- \1/' /etc/sudoers # Create `ansible` user with sudo permissions ENV ANSIBLE_USER=ansible SUDO_GROUP=wheel RUN set -xe && \ groupadd -r ${ANSIBLE_USER} && \ useradd -m -g ${ANSIBLE_USER} ${ANSIBLE_USER} && \ usermod -aG ${SUDO_GROUP} ${ANSIBLE_USER} && \ sed -i "/^%${SUDO_GROUP}/s/ALL\$/NOPASSWD:ALL/g" /etc/sudoers VOLUME [ "/sys/fs/cgroup", "/tmp", "/run" ] CMD [ "/usr/sbin/init" ] ================================================ FILE: molecule/resources/cleanup.yml ================================================ --- - name: Cleanup role-managed PowerDNS packages hosts: pdns vars: pdns_package_state: absent pdns_debug_symbols_package_state: absent pdns_backends_packages_state: absent pdns_mysql_packages_state: absent pdns_pgsql_packages_state: absent pdns_sqlite_package_state: absent pdns_backends: bind: {} gmysql: {} gpgsql: {} gsqlite3: {} lmdb: {} roles: - role: powerdns.pdns ================================================ FILE: molecule/resources/create.yml ================================================ --- - name: Create hosts: localhost connection: local gather_facts: false vars_files: - vars/molecule.yml tasks: - name: Detect host architecture for Docker platform selection ansible.builtin.set_fact: _molecule_host_arch: "{{ lookup('pipe', 'uname -m') | trim | lower }}" changed_when: false - name: Define Docker architecture/platform mappings ansible.builtin.set_fact: _molecule_arch_map: x86_64: amd64 amd64: amd64 aarch64: arm64 arm64: arm64 armv8l: arm64 changed_when: false - name: Set Docker target architecture and platform ansible.builtin.set_fact: molecule_docker_arch: "{{ _molecule_arch_map.get(_molecule_host_arch, _molecule_host_arch) }}" molecule_docker_platform: "linux/{{ _molecule_arch_map.get(_molecule_host_arch, _molecule_host_arch) }}" changed_when: false - name: Get list of service instances ansible.builtin.set_fact: molecule_service_instances: "{{ molecule_yml.platforms | selectattr('is_service', 'defined') | selectattr('is_service') | list }}" - name: Get list of platform instances ansible.builtin.set_fact: molecule_platform_instances: "{{ molecule_yml.platforms | difference(molecule_service_instances) }}" - name: Create Dockerfiles from platform names ansible.builtin.template: src: "Dockerfile.{{ item.dockerfile_tpl | default('default') }}.j2" dest: "{{ molecule_ephemeral_directory }}/Dockerfile_{{ item.name | regex_replace('[^a-zA-Z0-9_]', '_') }}" mode: '0644' with_items: "{{ molecule_platform_instances }}" register: platforms - name: Discover local Docker images community.docker.docker_image_info: name: "molecule_pdns/{{ item.item.name | lower | regex_replace('[^a-z0-9_.-]', '_') }}-{{ molecule_docker_arch }}" with_items: "{{ platforms.results }}" register: docker_images - name: Build an Ansible compatible image community.docker.docker_image: name: "molecule_pdns/{{ platforms.results[item].item.name | lower | regex_replace('[^a-z0-9_.-]', '_') }}-{{ molecule_docker_arch }}" source: build build: dockerfile: "{{ platforms.results[item].item.dockerfile | default(platforms.results[item].dest) }}" path: "{{ molecule_ephemeral_directory }}" platform: "{{ platforms.results[item].item.platform | default(molecule_docker_platform) }}" pull: true force_source: "{{ platforms.results[item].item.force | default(false) | bool }}" force_tag: "{{ platforms.results[item].item.force | default(false) | bool }}" loop: "{{ range(0, platforms.results | length) | list }}" loop_control: label: "{{ platforms.results[item].item.name }}" when: >- (platforms.results[item].get('changed', false) | bool) or ((docker_images.results[item].images | default([])) | length == 0) or (((docker_images.results[item].images | default([]) | first | default({})).Architecture | default('')) != molecule_docker_arch) or (platforms.results[item].item.force | default(false) | bool) - name: Create molecule instance(s) community.docker.docker_container: name: "{{ item.name }}" hostname: "{{ item.name }}" image: "{{ item.image }}" platform: "{{ item.platform | default(molecule_docker_platform) }}" state: started recreate: false env: "{{ item.env | default(omit) }}" privileged: "no" volumes: "{{ item.volumes | default(omit) }}" with_items: "{{ molecule_service_instances }}" - name: Create the required Services instance(s) community.docker.docker_container: name: "{{ item.name }}" hostname: "{{ item.name }}" image: "molecule_pdns/{{ item.name | lower | regex_replace('[^a-z0-9_.-]', '_') }}-{{ molecule_docker_arch }}" platform: "{{ item.platform | default(molecule_docker_platform) }}" links: "{{ molecule_service_instances | map(attribute='name') | list }}" command: "{{ item.command | default(omit) }}" state: started recreate: false privileged: "yes" volumes: # Mount the cgroups fs to allow SystemD to run into the containers - "/sys/fs/cgroup:/sys/fs/cgroup:rw" cgroupns_mode: host with_items: "{{ molecule_platform_instances }}" ================================================ FILE: molecule/resources/destroy.yml ================================================ --- - name: Destroy the Molecule Test Resources hosts: localhost connection: local gather_facts: false vars_files: - vars/molecule.yml tasks: - name: Destroy the target Platforms instance(s) community.docker.docker_container: name: "{{ item.name }}" state: absent force_kill: "{{ item.force_kill | default(true) }}" with_items: "{{ molecule_yml.platforms }}" ================================================ FILE: molecule/resources/prepare.yml ================================================ --- - name: Prepare the Molecule Test Resources hosts: pdns tasks: # Make sure the default MySQL and SQLite # schemas are installed in /usr/share/doc/ - name: Disable the YUM 'nodocs' option ansible.builtin.lineinfile: line: tsflags=nodocs dest: /etc/yum.conf state: absent when: ansible_pkg_mgr == 'yum' - name: Disable the APT 'nodoc' option ansible.builtin.lineinfile: line: path-exclude=/usr/share/doc/* dest: /etc/dpkg/dpkg.cfg.d/excludes state: absent when: ansible_pkg_mgr == 'apt' - name: Disable the pacman 'NoExtract' option for docs ansible.builtin.replace: path: /etc/pacman.conf regexp: '^(\s*NoExtract\s*=\s*)usr/share/doc/\*(\s*)' replace: '\1\2' when: ansible_pkg_mgr == 'pacman' - name: Disable the pacman 'NoExtract' doc token in lists ansible.builtin.replace: path: /etc/pacman.conf regexp: '(\s+)usr/share/doc/\*' replace: '\1' when: ansible_pkg_mgr == 'pacman' # Install rsyslog to capture the PowerDNS Recursor log messages # when the service is not managed by systemd - name: Install rsyslog when: ansible_service_mgr != 'systemd' block: - name: Install rsyslog ansible.builtin.package: name: rsyslog state: present - name: Start rsyslog ansible.builtin.service: name: rsyslog state: started - name: Install dnspython and acl on Debian/Ubuntu ansible.builtin.apt: name: - python3-dnspython - acl state: present update_cache: true when: ansible_os_family == 'Debian' - name: Install dnspython on RHEL/Alma/Rocky/OL ansible.builtin.dnf: name: python3-dns state: present when: ansible_os_family == 'RedHat' - name: Install dnspython on Archlinux ansible.builtin.package: name: python-dnspython state: present when: ansible_pkg_mgr == 'pacman' ================================================ FILE: molecule/resources/tests/all/test_common.py ================================================ debian_os = ['debian', 'ubuntu'] rhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux'] archlinux_os = ['arch', 'archarm'] def test_distribution(host): assert host.system_info.distribution.lower() in debian_os + rhel_os + \ archlinux_os def test_package(host): distro = host.system_info.distribution.lower() if distro in debian_os: assert host.package('pdns-server').is_installed return if distro in rhel_os: assert host.package('pdns').is_installed return if distro in archlinux_os: # testinfra does not map "archarm" to ArchPackage, so query pacman directly if distro == 'archarm': assert host.run('pacman -Q powerdns').rc == 0 return assert host.package('powerdns').is_installed def test_service(host): # Using Ansible to mitigate some issues with the service test on debian-8 unit = 'pdns' for config_dir in ('/etc/powerdns', '/etc/pdns'): if host.file(f'{config_dir}/pdns-lmdb.conf').exists: unit = 'pdns@lmdb' break s = host.ansible('service', f'name={unit} state=started enabled=yes') assert s["changed"] is False ================================================ FILE: molecule/resources/tests/backend-bind/test_backend_bind.py ================================================ debian_os = ['debian', 'ubuntu'] rhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux'] archlinux_os = ['arch', 'archarm'] def _pdns_config_dir(host): if host.system_info.distribution.lower() in debian_os + archlinux_os: return '/etc/powerdns' return '/etc/pdns' def _bind_config_file(host): config_dir = _pdns_config_dir(host) bind_instance_conf = host.file(f'{config_dir}/pdns-bind.conf') if bind_instance_conf.exists: return bind_instance_conf return host.file(f'{config_dir}/pdns.conf') def test_config(host): config_dir = _pdns_config_dir(host) with host.sudo(): f = _bind_config_file(host) assert f.exists assert f.contains('launch+=bind') assert f.contains(f'bind-config={config_dir}/named.conf') def test_bind_configuration_files(host): config_dir = _pdns_config_dir(host) with host.sudo(): named_conf = host.file(f'{config_dir}/named.conf') zone_file = host.file(f'{config_dir}/bind.test.zone') assert named_conf.exists assert named_conf.contains('zone "bind.test" IN') assert named_conf.contains('file "bind.test.zone"') assert zone_file.exists assert zone_file.contains('SOA ns1.bind.test.') def test_bind_instance_service_is_active(host): cmd = host.run('systemctl is-active pdns@bind') assert cmd.rc == 0 assert cmd.stdout.strip() == 'active' ================================================ FILE: molecule/resources/tests/backend-lmdb/test_backend_lmdb.py ================================================ debian_os = ['debian', 'ubuntu'] rhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux'] archlinux_os = ['arch', 'archarm'] def _pdns_config_dir(host): if host.system_info.distribution.lower() in debian_os + archlinux_os: return '/etc/powerdns' return '/etc/pdns' def _lmdb_config_file(host): config_dir = _pdns_config_dir(host) lmdb_instance_conf = host.file(f'{config_dir}/pdns-lmdb.conf') if lmdb_instance_conf.exists: return lmdb_instance_conf return host.file(f'{config_dir}/pdns.conf') def test_package(host): if host.system_info.distribution.lower() in debian_os + rhel_os: p = host.package('pdns-backend-lmdb') assert p.is_installed def test_config(host): with host.sudo(): f = _lmdb_config_file(host) assert f.exists assert f.contains('launch+=lmdb') assert f.contains('lmdb-filename=/var/lib/powerdns/pdns.lmdb') def test_lmdb_instance_service_is_active(host): config_dir = _pdns_config_dir(host) instance_conf = host.file(f'{config_dir}/pdns-lmdb.conf') unit = 'pdns@lmdb' if instance_conf.exists else 'pdns' cmd = host.run(f'systemctl is-active {unit}') assert cmd.rc == 0 assert cmd.stdout.strip() == 'active' ================================================ FILE: molecule/resources/tests/backend-mariadb/test_backend_mariadb.py ================================================ debian_os = ['debian', 'ubuntu'] rhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux'] archlinux_os = ['arch', 'archarm'] def _pdns_config_dir(host): if host.system_info.distribution.lower() in debian_os + archlinux_os: return '/etc/powerdns' return '/etc/pdns' def _mariadb_config_file(host): config_dir = _pdns_config_dir(host) mariadb_instance_conf = host.file(f'{config_dir}/pdns-mariadb.conf') if mariadb_instance_conf.exists: return mariadb_instance_conf return host.file(f'{config_dir}/pdns.conf') def test_package(host): if host.system_info.distribution.lower() in debian_os + rhel_os: p = host.package('pdns-backend-mysql') assert p.is_installed def test_config(host): with host.sudo(): f = _mariadb_config_file(host) dbname = host.check_output('hostname -s').replace('.', '_') assert f.exists assert f.contains('launch+=gmysql:mariadb') assert f.contains('gmysql-mariadb-host=mariadb') assert f.contains('gmysql-mariadb-password=pdns') assert f.contains('gmysql-mariadb-dbname=' + dbname) assert f.contains('gmysql-mariadb-user=pdns') ================================================ FILE: molecule/resources/tests/backend-mysql/test_backend_mysql.py ================================================ debian_os = ['debian', 'ubuntu'] rhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux'] archlinux_os = ['arch', 'archarm'] def _pdns_config_dir(host): if host.system_info.distribution.lower() in debian_os + archlinux_os: return '/etc/powerdns' return '/etc/pdns' def _mysql_config_file(host): config_dir = _pdns_config_dir(host) mysql_instance_conf = host.file(f'{config_dir}/pdns-mysql.conf') if mysql_instance_conf.exists: return mysql_instance_conf return host.file(f'{config_dir}/pdns.conf') def test_package(host): if host.system_info.distribution.lower() in debian_os + rhel_os: p = host.package('pdns-backend-mysql') assert p.is_installed def test_config(host): with host.sudo(): f = _mysql_config_file(host) dbname = host.check_output('hostname -s').replace('.', '_') assert f.exists assert f.contains('launch+=gmysql:mysql') assert f.contains('gmysql-mysql-host=mysql') assert f.contains('gmysql-mysql-password=pdns') assert f.contains('gmysql-mysql-dbname=' + dbname) assert f.contains('gmysql-mysql-user=pdns') ================================================ FILE: molecule/resources/tests/backend-postgresql/test_backend_postgresql.py ================================================ debian_os = ['debian', 'ubuntu'] rhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux'] archlinux_os = ['arch', 'archarm'] def _pdns_config_dir(host): if host.system_info.distribution.lower() in debian_os + archlinux_os: return '/etc/powerdns' return '/etc/pdns' def _postgresql_config_file(host): config_dir = _pdns_config_dir(host) pgsql_instance_conf = host.file(f'{config_dir}/pdns-postgresql.conf') if pgsql_instance_conf.exists: return pgsql_instance_conf return host.file(f'{config_dir}/pdns.conf') def test_package(host): distribution = host.system_info.distribution.lower() if distribution in debian_os: package = host.package('pdns-backend-pgsql') assert package.is_installed if distribution in rhel_os: package = host.package('pdns-backend-postgresql') assert package.is_installed def test_config(host): with host.sudo(): f = _postgresql_config_file(host) dbname = host.check_output('hostname -s').replace('.', '_') assert f.exists assert f.contains('launch+=gpgsql') assert f.contains('gpgsql-host=postgresql') assert f.contains('gpgsql-password=pdns') assert f.contains('gpgsql-dbname=' + dbname) assert f.contains('gpgsql-user=pdns') def test_postgresql_instance_service_is_active(host): cmd = host.run('systemctl is-active pdns@postgresql') assert cmd.rc == 0 assert cmd.stdout.strip() == 'active' ================================================ FILE: molecule/resources/tests/backend-sqlite/test_backend_sqlite.py ================================================ debian_os = ['debian', 'ubuntu'] rhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux'] archlinux_os = ['arch', 'archarm'] def _pdns_config_dir(host): if host.system_info.distribution.lower() in debian_os + archlinux_os: return '/etc/powerdns' return '/etc/pdns' def _sqlite_config_file(host): config_dir = _pdns_config_dir(host) sqlite_instance_conf = host.file(f'{config_dir}/pdns-sqlite.conf') if sqlite_instance_conf.exists: return sqlite_instance_conf return host.file(f'{config_dir}/pdns.conf') def test_package(host): if host.system_info.distribution.lower() in debian_os + rhel_os: if host.system_info.distribution.lower() in debian_os: p = host.package('pdns-backend-sqlite3') if host.system_info.distribution.lower() in rhel_os: p = host.package('pdns-backend-sqlite') assert p.is_installed def test_config(host): with host.sudo(): f = _sqlite_config_file(host) assert f.exists assert f.contains('launch+=gsqlite3') assert f.contains('gsqlite3-database=/var/lib/powerdns/pdns.sqlite3') def test_database_exists(host): f = host.file('/var/lib/powerdns/pdns.sqlite3') user = 'pdns' if host.system_info.distribution.lower() in archlinux_os: user = 'powerdns' assert f.exists assert f.user == user assert f.group == user assert f.mode == 0o640 assert f.size > 10000 ================================================ FILE: molecule/resources/tests/backend-zones/test_backend_zones.py ================================================ def _normalize_zone(zone): return zone.rstrip('.') def _dns_lookup_rcode(host, zone, port): script = ( "import sys,dns.message,dns.query,dns.rdatatype;" "zone=sys.argv[1].rstrip('.');" "port=int(sys.argv[2]);" "query=dns.message.make_query(zone,dns.rdatatype.SOA);" "response=dns.query.udp(query,'127.0.0.1',port=port,timeout=3);" "print(int(response.rcode()))" ) command = f'python3 -c "{script}" "{zone}" "{port}"' result = host.run(command) assert result.rc == 0, result.stderr return int(result.stdout.strip()) def _pdnsutil_command(subcommand, zone=None, config_name=''): command_parts = ['pdnsutil'] if config_name: command_parts.append(f'--config-name={config_name}') command_parts.append(subcommand) if zone: command_parts.append(zone) return ' '.join(command_parts) def test_backend_zones_are_listed(host): expected_zones = ( ('lmdb.test', 'lmdb'), ('sqlite3.test', 'sqlite'), ('mysql.test', 'mysql'), ('mariadb.test', 'mariadb'), ('postgresql.test', 'postgresql'), ) for zone, config_name in expected_zones: cmd = host.run(_pdnsutil_command('list-all-zones', config_name=config_name)) assert cmd.rc == 0 discovered_zones = { _normalize_zone(line.strip()) for line in cmd.stdout.splitlines() if line.strip() } assert zone in discovered_zones def test_backend_zones_are_queryable(host): expected_zones = ( ('lmdb.test', 'lmdb'), ('sqlite3.test', 'sqlite'), ('mysql.test', 'mysql'), ('mariadb.test', 'mariadb'), ('postgresql.test', 'postgresql'), ) for zone, config_name in expected_zones: cmd = host.run(_pdnsutil_command('list-zone', zone=zone, config_name=config_name)) assert cmd.rc == 0 assert zone in cmd.stdout def test_backend_zones_dns_lookup_noerror(host): expected_zones = ( ('lmdb.test', 54), ('sqlite3.test', 55), ('mysql.test', 56), ('mariadb.test', 57), ('bind.test', 58), ('postgresql.test', 59), ) for zone, port in expected_zones: assert _dns_lookup_rcode(host, zone, port) == 0 ================================================ FILE: molecule/resources/tests/repo-48/test_repo_48.py ================================================ import re debian_os = ['debian', 'ubuntu'] rhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux'] def _release_major(host): release = host.system_info.release match = re.match(r'^(\d+)', release) return int(match.group(1)) if match else 0 def _supports_deb822(host): distro = host.system_info.distribution.lower() major = _release_major(host) if distro == 'ubuntu': return major >= 22 if distro == 'debian': return True return False def _assert_debian_repo_layout(host): distro = host.system_info.distribution.lower() if distro not in debian_os: return sources_file = host.file('/etc/apt/sources.list.d/powerdns-auth-48.sources') list_file = host.file('/etc/apt/sources.list.d/powerdns-auth-48.list') if _supports_deb822(host): assert sources_file.exists assert not list_file.exists else: assert list_file.exists assert not sources_file.exists def _repo_file(host): distro = host.system_info.distribution.lower() if distro in debian_os: if _supports_deb822(host): return host.file('/etc/apt/sources.list.d/powerdns-auth-48.sources') return host.file('/etc/apt/sources.list.d/powerdns-auth-48.list') if distro in rhel_os: return host.file('/etc/yum.repos.d/powerdns-auth-48.repo') return None def test_repo_file(host): _assert_debian_repo_layout(host) f = _repo_file(host) assert f is not None assert f.exists assert f.user == 'root' assert f.group == 'root' def test_pdns_repo(host): f = _repo_file(host) assert f is not None assert f.exists assert f.contains('auth-48') def test_repo_pinning_file(host): if host.system_info.distribution.lower() in debian_os: f = host.file('/etc/apt/preferences.d/pdns') assert f.exists assert f.user == 'root' assert f.group == 'root' f.contains('Package: pdns-*') f.contains('Pin: origin repo.powerdns.com') f.contains('Pin-Priority: 600') def test_pdns_version(host): cmd = host.run('/usr/sbin/pdns_server --version') assert 'PowerDNS Authoritative Server' in cmd.stderr assert '4.8' in cmd.stderr ================================================ FILE: molecule/resources/tests/repo-49/test_repo_49.py ================================================ import re debian_os = ['debian', 'ubuntu'] rhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux'] def _release_major(host): release = host.system_info.release match = re.match(r'^(\d+)', release) return int(match.group(1)) if match else 0 def _supports_deb822(host): distro = host.system_info.distribution.lower() major = _release_major(host) if distro == 'ubuntu': return major >= 22 if distro == 'debian': return True return False def _assert_debian_repo_layout(host): distro = host.system_info.distribution.lower() if distro not in debian_os: return sources_file = host.file('/etc/apt/sources.list.d/powerdns-auth-49.sources') list_file = host.file('/etc/apt/sources.list.d/powerdns-auth-49.list') if _supports_deb822(host): assert sources_file.exists assert not list_file.exists else: assert list_file.exists assert not sources_file.exists def _repo_file(host): distro = host.system_info.distribution.lower() if distro in debian_os: if _supports_deb822(host): return host.file('/etc/apt/sources.list.d/powerdns-auth-49.sources') return host.file('/etc/apt/sources.list.d/powerdns-auth-49.list') if distro in rhel_os: return host.file('/etc/yum.repos.d/powerdns-auth-49.repo') return None def test_repo_file(host): _assert_debian_repo_layout(host) f = _repo_file(host) assert f is not None assert f.exists assert f.user == 'root' assert f.group == 'root' def test_pdns_repo(host): f = _repo_file(host) assert f is not None assert f.exists assert f.contains('auth-49') def test_repo_pinning_file(host): if host.system_info.distribution.lower() in debian_os: f = host.file('/etc/apt/preferences.d/pdns') assert f.exists assert f.user == 'root' assert f.group == 'root' f.contains('Package: pdns-*') f.contains('Pin: origin repo.powerdns.com') f.contains('Pin-Priority: 600') def test_pdns_version(host): cmd = host.run('/usr/sbin/pdns_server --version') output = f'{cmd.stdout}\n{cmd.stderr}' assert 'PowerDNS Authoritative Server' in output assert '4.9' in output ================================================ FILE: molecule/resources/tests/repo-50/test_repo_50.py ================================================ import re debian_os = ['debian', 'ubuntu'] rhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux'] def _release_major(host): release = host.system_info.release match = re.match(r'^(\d+)', release) return int(match.group(1)) if match else 0 def _supports_deb822(host): distro = host.system_info.distribution.lower() major = _release_major(host) if distro == 'ubuntu': return major >= 22 if distro == 'debian': return True return False def _assert_debian_repo_layout(host): distro = host.system_info.distribution.lower() if distro not in debian_os: return sources_file = host.file('/etc/apt/sources.list.d/powerdns-auth-50.sources') list_file = host.file('/etc/apt/sources.list.d/powerdns-auth-50.list') if _supports_deb822(host): assert sources_file.exists assert not list_file.exists else: assert list_file.exists assert not sources_file.exists def _repo_file(host): distro = host.system_info.distribution.lower() if distro in debian_os: if _supports_deb822(host): return host.file('/etc/apt/sources.list.d/powerdns-auth-50.sources') return host.file('/etc/apt/sources.list.d/powerdns-auth-50.list') if distro in rhel_os: return host.file('/etc/yum.repos.d/powerdns-auth-50.repo') return None def test_repo_file(host): _assert_debian_repo_layout(host) f = _repo_file(host) assert f is not None assert f.exists assert f.user == 'root' assert f.group == 'root' def test_pdns_repo(host): f = _repo_file(host) assert f is not None assert f.exists assert f.contains('auth-50') def test_repo_pinning_file(host): if host.system_info.distribution.lower() in debian_os: f = host.file('/etc/apt/preferences.d/pdns') assert f.exists assert f.user == 'root' assert f.group == 'root' f.contains('Package: pdns-*') f.contains('Pin: origin repo.powerdns.com') f.contains('Pin-Priority: 600') def test_pdns_version(host): cmd = host.run('/usr/sbin/pdns_server --version') output = f'{cmd.stdout}\n{cmd.stderr}' assert 'PowerDNS Authoritative Server' in output assert '5.0' in output ================================================ FILE: molecule/resources/tests/repo-master/test_repo_master.py ================================================ import re debian_os = ['debian', 'ubuntu'] rhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux'] def _release_major(host): release = host.system_info.release match = re.match(r'^(\d+)', release) return int(match.group(1)) if match else 0 def _supports_deb822(host): distro = host.system_info.distribution.lower() major = _release_major(host) if distro == 'ubuntu': return major >= 22 if distro == 'debian': return True return False def _assert_debian_repo_layout(host): distro = host.system_info.distribution.lower() if distro not in debian_os: return sources_file = host.file('/etc/apt/sources.list.d/powerdns-auth-master.sources') list_file = host.file('/etc/apt/sources.list.d/powerdns-auth-master.list') if _supports_deb822(host): assert sources_file.exists assert not list_file.exists else: assert list_file.exists assert not sources_file.exists def _repo_file(host): distro = host.system_info.distribution.lower() if distro in debian_os: if _supports_deb822(host): return host.file('/etc/apt/sources.list.d/powerdns-auth-master.sources') return host.file('/etc/apt/sources.list.d/powerdns-auth-master.list') if distro in rhel_os: return host.file('/etc/yum.repos.d/powerdns-auth-master.repo') return None def test_repo_file(host): _assert_debian_repo_layout(host) f = _repo_file(host) assert f is not None assert f.exists assert f.user == 'root' assert f.group == 'root' def test_pdns_repo(host): f = _repo_file(host) assert f is not None assert f.exists assert f.contains('auth-master') def test_repo_pinning_file(host): if host.system_info.distribution.lower() in debian_os: f = host.file('/etc/apt/preferences.d/pdns') assert f.exists assert f.user == 'root' assert f.group == 'root' f.contains('Package: pdns-*') f.contains('Pin: origin repo.powerdns.com') f.contains('Pin-Priority: 600') def test_pdns_version(host): cmd = host.run('/usr/sbin/pdns_server --version') assert 'PowerDNS Authoritative Server' in cmd.stderr or 'PowerDNS Authoritative Server' in cmd.stdout assert 'master' in cmd.stderr or 'master' in cmd.stdout ================================================ FILE: molecule/resources/tests/service-mask/test_service_mask.py ================================================ def test_default_pdns_service_is_masked_and_stopped(host): smgr = host.ansible("setup")["ansible_facts"]["ansible_service_mgr"] if smgr != 'systemd': return is_enabled = host.run('systemctl is-enabled pdns') assert is_enabled.stdout.strip() == 'masked' is_active = host.run('systemctl is-active pdns') assert is_active.stdout.strip() != 'active' # Port 53 may appear as listening in containerized environments even when no # default pdns process is running. Validate behavior instead: querying a # zone provisioned on instance backends must not succeed on the default port. query = host.run( """python3 - <<'PY' import dns.exception import dns.message import dns.query import dns.rdatatype query = dns.message.make_query('lmdb.test', dns.rdatatype.SOA) try: response = dns.query.udp(query, '127.0.0.1', port=53, timeout=2) print(response.rcode()) except dns.exception.Timeout: print('TIMEOUT') PY""" ) assert query.rc == 0, query.stderr assert query.stdout.strip() in ('TIMEOUT', '5') ================================================ FILE: molecule/resources/tests/systemd-no-override/test_override.py ================================================ def test_systemd_override(host): smgr = host.ansible("setup")["ansible_facts"]["ansible_service_mgr"] if smgr == 'systemd': fname = '/etc/systemd/system/pdns.service.d/override.conf' f = host.file(fname) assert not f.exists ================================================ FILE: molecule/resources/tests/systemd-override/test_override.py ================================================ def test_systemd_override(host): smgr = host.ansible("setup")["ansible_facts"]["ansible_service_mgr"] if smgr == 'systemd': fname = '/etc/systemd/system/pdns.service.d/override.conf' for config_dir in ('/etc/powerdns', '/etc/pdns'): if host.file(f'{config_dir}/pdns-lmdb.conf').exists: fname = '/etc/systemd/system/pdns@lmdb.service.d/override.conf' break f = host.file(fname) assert f.exists assert f.user == 'root' assert f.group == 'root' assert f.contains('LimitCORE=infinity') ================================================ FILE: molecule/resources/vars/molecule.yml ================================================ --- molecule_file: "{{ lookup('env', 'MOLECULE_FILE') }}" molecule_ephemeral_directory: "{{ lookup('env', 'MOLECULE_EPHEMERAL_DIRECTORY') }}" molecule_scenario_directory: "{{ lookup('env', 'MOLECULE_SCENARIO_DIRECTORY') }}" role_file: requirements.yml requirements_file: requirements.yml molecule_yml: "{{ lookup('file', molecule_file) | from_yaml }}" ================================================ FILE: molecule/resources/vars/pdns-backend-bind.yml ================================================ --- # Bind backend profile pdns_backends_bind: bind: config: "{{ pdns_config_dir }}/named.conf" pdns_instance: service_name: "pdns@bind" service_enabled: "no" config_file: "pdns-bind.conf" config_name: "bind" config_overrides: local-port: "58" webserver-port: "8006" zone: "bind.test" pdns_config_files_bind: - dest: named.conf mode: "0640" content: | options { directory "{{ pdns_config_dir }}"; }; zone "bind.test" IN { type master; file "bind.test.zone"; }; - dest: bind.test.zone mode: "0640" content: | $TTL 60 @ IN SOA ns1.bind.test. hostmaster.bind.test. 2026022101 3600 1800 1209600 60 @ IN NS ns1.bind.test. ns1 IN A 127.0.0.1 @ IN A 127.0.0.58 pdns_config_overrides_bind: {} pdns_backends: "{{ pdns_backends_bind }}" pdns_config_files: "{{ pdns_config_files_bind }}" ================================================ FILE: molecule/resources/vars/pdns-backend-lmdb.yml ================================================ --- # LMDB backend profile pdns_backends_lmdb: lmdb: filename: /var/lib/powerdns/pdns.lmdb pdns_instance: service_name: "pdns@lmdb" service_enabled: "yes" config_file: "pdns-lmdb.conf" config_name: "lmdb" config_overrides: local-port: "54" webserver-port: "8002" zone: "lmdb.test" pdns_lmdb_databases_locations_lmdb: - '/var/lib/powerdns/pdns.lmdb' pdns_config_overrides_lmdb: {} pdns_backends: "{{ pdns_backends_lmdb }}" pdns_lmdb_databases_locations: "{{ pdns_lmdb_databases_locations_lmdb }}" ================================================ FILE: molecule/resources/vars/pdns-backend-mariadb.yml ================================================ --- # MariaDB backend profile pdns_backends_mariadb: 'gmysql:mariadb': host: "mariadb" dbname: "{{ ansible_hostname | replace('.', '_') }}" user: "pdns_{{ ansible_hostname | replace('.', '_') | replace('-', '_') }}" password: pdns pdns_instance: service_name: "pdns@mariadb" service_enabled: "no" config_file: "pdns-mariadb.conf" config_name: "mariadb" config_overrides: local-port: "57" webserver-port: "8005" zone: "mariadb.test" pdns_mysql_databases_credentials_mariadb: 'gmysql:mariadb': priv_user: root priv_password: "{{ ansible_env.MARIADB_ENV_MARIADB_ROOT_PASSWORD | default('pdns') }}" priv_host: - '%' - 'localhost' # Molecule uses a remote MariaDB service container, so connections must use TCP. pdns_mysql_query_use_socket_mariadb: false pdns_mysql_schema_on_first_node_only: false pdns_backends_mysql_cmd: "mysql" pdns_mysql_cli_extra_args_mariadb: >- {{ '--ssl-mode=DISABLED' if ansible_distribution == 'Ubuntu' else '--skip-ssl' }} pdns_mysql_cli_extra_args: "{{ pdns_mysql_cli_extra_args_mariadb }}" pdns_config_overrides_mariadb: {} pdns_backends: "{{ pdns_backends_mariadb }}" pdns_mysql_databases_credentials: "{{ pdns_mysql_databases_credentials_mariadb }}" pdns_mysql_query_use_socket: "{{ pdns_mysql_query_use_socket_mariadb }}" ================================================ FILE: molecule/resources/vars/pdns-backend-mysql.yml ================================================ --- # MySQL backend profile pdns_backends_mysql: 'gmysql:mysql': host: "mysql" dbname: "{{ ansible_hostname | replace('.', '_') }}" user: "pdns_{{ ansible_hostname | replace('.', '_') | replace('-', '_') }}" password: pdns pdns_instance: service_name: "pdns@mysql" service_enabled: "no" config_file: "pdns-mysql.conf" config_name: "mysql" config_overrides: local-port: "56" webserver-port: "8004" zone: "mysql.test" pdns_mysql_databases_credentials_mysql: 'gmysql:mysql': priv_user: root priv_password: "{{ ansible_env.MYSQL_ENV_MYSQL_ROOT_PASSWORD | default('pdns') }}" priv_host: - '%' - 'localhost' # MySQL 8.4/9 disables mysql_native_password by default. auth_plugin: caching_sha2_password # Molecule uses a remote MySQL service container, so connections must use TCP. pdns_mysql_query_use_socket_mysql: false pdns_mysql_schema_on_first_node_only: false pdns_backends_mysql_cmd: "mysql" pdns_mysql_cli_extra_args_mysql: >- {{ '--ssl-mode=DISABLED --get-server-public-key' if ansible_distribution == 'Ubuntu' else '--skip-ssl' }} pdns_mysql_cli_extra_args: "{{ pdns_mysql_cli_extra_args_mysql }}" pdns_config_overrides_mysql: {} pdns_backends: "{{ pdns_backends_mysql }}" pdns_mysql_databases_credentials: "{{ pdns_mysql_databases_credentials_mysql }}" pdns_mysql_query_use_socket: "{{ pdns_mysql_query_use_socket_mysql }}" ================================================ FILE: molecule/resources/vars/pdns-backend-postgresql.yml ================================================ --- # PostgreSQL backend profile pdns_backends_pgsql: gpgsql: host: "postgresql" dbname: "{{ ansible_hostname | replace('.', '_') }}" user: "pdns_{{ ansible_hostname | replace('.', '_') | replace('-', '_') }}" password: pdns pdns_instance: service_name: "pdns@postgresql" service_enabled: "no" config_file: "pdns-postgresql.conf" config_name: "postgresql" config_overrides: local-port: "59" webserver-port: "8007" zone: "postgresql.test" pdns_pgsql_databases_credentials_pgsql: gpgsql: priv_user: postgres priv_password: "{{ ansible_env.POSTGRESQL_ENV_POSTGRES_PASSWORD | default('pdns') }}" pdns_pgsql_query_use_socket_pgsql: false pdns_pgsql_schema_on_first_node_only: false pdns_config_overrides_pgsql: {} pdns_backends: "{{ pdns_backends_pgsql }}" pdns_pgsql_databases_credentials: "{{ pdns_pgsql_databases_credentials_pgsql }}" pdns_pgsql_query_use_socket: "{{ pdns_pgsql_query_use_socket_pgsql }}" ================================================ FILE: molecule/resources/vars/pdns-backend-sqlite3.yml ================================================ --- # SQLite3 backend profile pdns_backends_sqlite3: gsqlite3: database: /var/lib/powerdns/pdns.sqlite3 dnssec: true pdns_instance: service_name: "pdns@sqlite" service_enabled: "no" config_file: "pdns-sqlite.conf" config_name: "sqlite" config_overrides: local-port: "55" webserver-port: "8003" zone: "sqlite3.test" pdns_sqlite_databases_locations_sqlite3: - '/var/lib/powerdns/pdns.sqlite3' pdns_config_overrides_sqlite3: {} pdns_backends: "{{ pdns_backends_sqlite3 }}" pdns_sqlite_databases_locations: "{{ pdns_sqlite_databases_locations_sqlite3 }}" ================================================ FILE: molecule/resources/vars/pdns-common.yml ================================================ --- ## # PowerDNS Configuration ## pdns_config_common: # Turns on primary operations primary: true include-dir: "user_pdns.d" # Listen Address local-address: "127.0.0.1" local-port: "53" # API Configuration api: true api-key: "powerdns" # Embedded webserver webserver: true webserver-address: "127.0.0.1" webserver-port: "8001" pdns_service_overrides: LimitCORE: infinity pdns_config_additional_dirs: - path: "{{ pdns_config_common['include-dir'] }}" mode: "0775" pdns_config_files: - dest: "{{ pdns_config_common['include-dir'] }}/user.config" mode: "0750" content: | # my additional config file version-string=powerdns ================================================ FILE: molecule/resources/vars/pdns-no-overrides.yml ================================================ --- ## # PowerDNS Configuration ## pdns_config: # Turns on primary operations primary: true # Listen Address local-address: "127.0.0.1" local-port: "53" # API Configuration api: true api-key: "powerdns" # Embedded webserver webserver: true webserver-address: "0.0.0.0" webserver-port: "8001" pdns_service_overrides: {} ================================================ FILE: molecule/resources/vars/pdns-os-repos.yml ================================================ --- ## # PowerDNS Configuration ## _pdns_config_base: # Listen Address local-address: "127.0.0.1" local-port: "53" # API Configuration api: true api-key: "powerdns" # Embedded webserver webserver: true webserver-address: "0.0.0.0" webserver-port: "8001" # Turns on master operations _pdns_config_primary: primary: true pdns_config: "{{ _pdns_config_base | combine(_pdns_config_legacy | default(_pdns_config_primary), recursive=True) }}" pdns_service_overrides: LimitCORE: infinity ================================================ FILE: molecule/resources/vars/pdns-repo-48.yml ================================================ --- ## # PowerDNS 4.8.x Repository ## pdns_install_repo: "{{ pdns_auth_powerdns_repo_48 }}" ================================================ FILE: molecule/resources/vars/pdns-repo-49.yml ================================================ --- ## # PowerDNS 4.9.x Repository ## pdns_install_repo: "{{ pdns_auth_powerdns_repo_49 }}" ================================================ FILE: molecule/resources/vars/pdns-repo-50.yml ================================================ --- ## # PowerDNS 5.0.x Repository ## pdns_install_repo: "{{ pdns_auth_powerdns_repo_50 }}" ================================================ FILE: molecule/resources/vars/pdns-repo-master.yml ================================================ --- ## # PowerDNS Master Repository ## pdns_install_repo: "{{ pdns_auth_powerdns_repo_master }}" ================================================ FILE: requirements.yml ================================================ --- collections: - name: community.mysql - name: community.postgresql - name: community.general version: "<11.0.0" - name: community.docker version: "<5.0.0" - name: ansible.posix ================================================ FILE: tasks/configure.yml ================================================ --- - name: Set up systemd override when: ansible_service_mgr == "systemd" tags: - config block: - name: Ensure the override directory exists (systemd) ansible.builtin.file: name: "/etc/systemd/system/{{ pdns_service_name }}.service.d" state: directory owner: root group: root mode: "0755" - name: Override the PowerDNS Authoritative Server unit (systemd) ansible.builtin.template: src: "override-service.systemd.conf.j2" dest: "/etc/systemd/system/{{ pdns_service_name }}.service.d/override.conf" owner: root group: root mode: "0644" notify: - reload systemd - restart pdns when: pdns_service_overrides | length > 0 - name: Ensure that the PowerDNS configuration directory exists ansible.builtin.file: name: "{{ pdns_config_dir }}" state: directory owner: "{{ pdns_file_owner }}" group: "{{ pdns_file_group }}" mode: "0750" tags: - config - name: Generate the PowerDNS configuration ansible.builtin.template: src: pdns.conf.j2 dest: "{{ pdns_config_dir }}/{{ pdns_config_file }}" owner: "{{ pdns_file_owner }}" group: "{{ pdns_file_group }}" mode: "0640" notify: restart pdns tags: - config - name: Ensure configured PowerDNS additional directories exist ansible.builtin.file: name: "{{ item.path | default(item) }}" state: directory owner: "{{ item.owner | default(pdns_file_owner) }}" group: "{{ item.group | default(pdns_file_group) }}" mode: "{{ item.mode | default('0750') }}" loop: "{{ pdns_config_additional_dirs }}" loop_control: label: "{{ item.path | default(item) }}" notify: restart pdns tags: - config - name: Ensure directories for configured PowerDNS extra files exist ansible.builtin.file: name: "{{ _pdns_config_file_dest | dirname }}" state: directory owner: "{{ item.dir_owner | default(item.owner | default(pdns_file_owner)) }}" group: "{{ item.dir_group | default(item.group | default(pdns_file_group)) }}" mode: "{{ item.dir_mode | default('0750') }}" vars: _pdns_config_file_dest: >- {{ item.dest if (item.dest is match('^/')) else (pdns_config_dir ~ '/' ~ item.dest) }} loop: "{{ pdns_config_files }}" loop_control: label: "{{ item.dest }}" notify: restart pdns tags: - config - name: Copy configured PowerDNS extra files ansible.builtin.copy: content: "{{ item.content | default(omit) }}" src: "{{ item.src | default(omit) }}" dest: "{{ _pdns_config_file_dest }}" owner: "{{ item.owner | default(pdns_file_owner) }}" group: "{{ item.group | default(pdns_file_group) }}" mode: "{{ item.mode | default('0640') }}" vars: _pdns_config_file_dest: >- {{ item.dest if (item.dest is match('^/')) else (pdns_config_dir ~ '/' ~ item.dest) }} loop: "{{ pdns_config_files }}" loop_control: label: "{{ item.dest }}" notify: restart pdns tags: - config ================================================ FILE: tasks/database-lmdb.yml ================================================ --- - name: Ensure that the directories containing the PowerDNS LMDB databases exist ansible.builtin.file: name: "{{ item | dirname }}" owner: "{{ pdns_user }}" group: "{{ pdns_group }}" state: directory mode: "0750" with_items: "{{ pdns_lmdb_databases_locations }}" tags: - config ================================================ FILE: tasks/database-mysql.yml ================================================ --- - name: Install the MySQL dependencies ansible.builtin.package: name: "{{ pdns_mysql_packages }}" state: "{{ pdns_mysql_packages_state }}" tags: - install - name: Manage the PowerDNS MySQL databases when: - pdns_package_state != 'absent' - pdns_mysql_manage_database | bool tags: - config block: - name: Create the PowerDNS MySQL databases community.mysql.mysql_db: login_user: "{{ item['value']['priv_user'] }}" login_password: "{{ item['value']['priv_password'] }}" login_host: "{{ item['value']['host'] | default('localhost') if not pdns_mysql_query_use_socket else omit }}" login_port: "{{ item['value']['port'] | default('3306') if not pdns_mysql_query_use_socket else omit }}" login_unix_socket: "{{ pdns_mysql_unix_socket if pdns_mysql_query_use_socket else omit }}" name: "{{ item['value']['dbname'] }}" state: present when: - item.key.split(':')[0] == 'gmysql' - item['value']['priv_user'] is defined - item['value']['priv_password'] is defined run_once: "{{ pdns_mysql_schema_on_first_node_only }}" throttle: 1 no_log: "{{ not pdns_verbose }}" with_dict: "{{ pdns_backends | combine(pdns_mysql_databases_credentials, recursive=True) }}" - name: Grant PowerDNS access to the MySQL databases community.mysql.mysql_user: login_user: "{{ item[0]['priv_user'] }}" login_password: "{{ item[0]['priv_password'] }}" login_host: "{{ item[0]['host'] | default('localhost') if not pdns_mysql_query_use_socket else omit }}" login_port: "{{ item[0]['port'] | default('3306') if not pdns_mysql_query_use_socket else omit }}" login_unix_socket: "{{ pdns_mysql_unix_socket if pdns_mysql_query_use_socket else omit }}" name: "{{ item[0]['user'] }}" password: "{{ item[0]['password'] if (_pdns_mysql_auth_plugin_effective | length == 0) else omit }}" plugin: "{{ _pdns_mysql_auth_plugin_effective if (_pdns_mysql_auth_plugin_effective | length > 0) else omit }}" plugin_auth_string: "{{ item[0]['password'] if (_pdns_mysql_auth_plugin_effective | length > 0) else omit }}" update_password: >- {{ _pdns_mysql_user_update_password_effective if (_pdns_mysql_user_update_password_effective | length > 0) else ('on_create' if (_pdns_mysql_auth_plugin_effective | length > 0) else 'always') }} host: "{{ item[1] }}" priv: "{{ item[0]['dbname'] }}.*:ALL" append_privs: true state: present when: pdns_mysql_databases_credentials | length > 0 no_log: "{{ not pdns_verbose }}" vars: _pdns_mysql_auth_plugin_effective: "{{ item[0]['auth_plugin'] | default(pdns_mysql_auth_plugin) }}" _pdns_mysql_user_update_password_effective: "{{ item[0]['update_password'] | default(pdns_mysql_user_update_password) }}" run_once: "{{ pdns_mysql_schema_on_first_node_only }}" throttle: 1 with_subelements: - "{{ pdns_backends | combine(pdns_mysql_databases_credentials, recursive=True) }}" - priv_host - skip_missing: true - name: Check if the MySQL databases are empty ansible.builtin.command: cmd: >- {{ pdns_backends_mysql_cmd }} --user="{{ item['value']['user'] }}" --password="{{ item['value']['password'] }}" {{ pdns_mysql_cli_extra_args }} {% if pdns_mysql_query_use_socket %} --socket="{{ pdns_mysql_unix_socket }}" {% else %} --host="{{ item['value']['host'] | default('localhost') }}" --port="{{ item['value']['port'] | default('3306') }}"{% endif %} --batch --skip-column-names --execute="SELECT COUNT(DISTINCT table_name) FROM information_schema.columns WHERE table_schema = '{{ item['value']['dbname'] }}'" when: - pdns_mysql_schema_load - item.key.split(':')[0] == 'gmysql' with_dict: "{{ pdns_backends }}" register: _pdns_check_mysql_db no_log: "{{ not pdns_verbose }}" changed_when: false - name: Determine location of the SQL file ansible.builtin.shell: cmd: | for p in /usr/share/doc/pdns-backend-mysql-{{ _pdns_running_version }}/schema.mysql.sql \ /usr/share/doc/pdns-backend-mysql/schema.mysql.sql \ /usr/share/pdns-backend-mysql/schema/schema.mysql.sql \ /usr/share/dbconfig-common/data/pdns-backend-mysql/install/mysql \ /usr/share/doc/powerdns/schema.mysql.sql \ /usr/share/doc/pdns/schema.mysql.sql; do if [ -f $p ]; then echo $p exit 0 fi done echo "Can't determine path to MySQL schema">&2 exit 1 changed_when: false register: _pdns_mysql_schema_file_detected when: - pdns_mysql_schema_load - pdns_mysql_schema_file | length == 0 - name: Set the schema file variable ansible.builtin.set_fact: _pdns_mysql_schema_file_to_use: >- {{ _pdns_mysql_schema_file_detected.stdout if pdns_mysql_schema_file | length == 0 else pdns_mysql_schema_file }} when: pdns_mysql_schema_load - name: Import the PowerDNS MySQL schema ansible.builtin.shell: cmd: >- {{ pdns_backends_mysql_cmd }} --user="{{ item['item']['value']['user'] }}" --password="{{ item['item']['value']['password'] }}" {{ pdns_mysql_cli_extra_args }} {% if pdns_mysql_query_use_socket %} --socket="{{ pdns_mysql_unix_socket }}" {% else %} --host="{{ item['item']['value']['host'] | default('localhost') }}" --port="{{ item['item']['value']['port'] | default('3306') }}" {% endif %} --database="{{ item.item['value']['dbname'] }}" < "{{ _pdns_mysql_schema_file_to_use }}" no_log: "{{ not pdns_verbose }}" run_once: "{{ pdns_mysql_schema_on_first_node_only }}" throttle: 1 changed_when: item['stdout'] == '0' when: - pdns_mysql_schema_load - item['item']['key'].split(':')[0] == 'gmysql' - item['stdout'] == '0' with_items: "{{ _pdns_check_mysql_db['results'] }}" ================================================ FILE: tasks/database-pgsql.yml ================================================ --- - name: Install the PostgreSQL dependencies ansible.builtin.package: name: "{{ pdns_pgsql_packages }}" state: "{{ pdns_pgsql_packages_state }}" tags: - install - name: Manage the PowerDNS PostgreSQL databases when: - pdns_package_state != 'absent' - pdns_pgsql_manage_database | bool tags: - config block: - name: Create PowerDNS PostgreSQL users community.postgresql.postgresql_user: login_user: "{{ item['value']['priv_user'] }}" login_password: "{{ item['value']['priv_password'] }}" login_host: "{{ item['value']['host'] | default('localhost') if not pdns_pgsql_query_use_socket else omit }}" login_port: "{{ item['value']['port'] | default('5432') if not pdns_pgsql_query_use_socket else omit }}" login_unix_socket: "{{ pdns_pgsql_unix_socket if pdns_pgsql_query_use_socket else omit }}" name: "{{ item['value']['user'] }}" password: "{{ item['value']['password'] }}" role_attr_flags: "LOGIN,NOSUPERUSER,NOCREATEDB,NOCREATEROLE,NOREPLICATION" state: present when: - item.key.split(':')[0] == 'gpgsql' - item['value']['priv_user'] is defined - item['value']['priv_password'] is defined run_once: "{{ pdns_pgsql_schema_on_first_node_only }}" throttle: 1 no_log: "{{ not pdns_verbose }}" with_dict: "{{ pdns_backends | combine(pdns_pgsql_databases_credentials, recursive=True) }}" - name: Create the PowerDNS PostgreSQL databases community.postgresql.postgresql_db: login_user: "{{ item['value']['priv_user'] }}" login_password: "{{ item['value']['priv_password'] }}" login_host: "{{ item['value']['host'] | default('localhost') if not pdns_pgsql_query_use_socket else omit }}" login_port: "{{ item['value']['port'] | default('5432') if not pdns_pgsql_query_use_socket else omit }}" login_unix_socket: "{{ pdns_pgsql_unix_socket if pdns_pgsql_query_use_socket else omit }}" name: "{{ item['value']['dbname'] }}" owner: "{{ item['value']['user'] }}" state: present when: - item.key.split(':')[0] == 'gpgsql' - item['value']['priv_user'] is defined - item['value']['priv_password'] is defined run_once: "{{ pdns_pgsql_schema_on_first_node_only }}" throttle: 1 no_log: "{{ not pdns_verbose }}" with_dict: "{{ pdns_backends | combine(pdns_pgsql_databases_credentials, recursive=True) }}" - name: Check if the PostgreSQL databases are empty community.postgresql.postgresql_query: login_db: "{{ item['value']['dbname'] }}" login_user: "{{ item['value']['user'] }}" login_password: "{{ item['value']['password'] }}" login_host: "{{ item['value']['host'] | default('localhost') if not pdns_pgsql_query_use_socket else omit }}" login_port: "{{ item['value']['port'] | default('5432') if not pdns_pgsql_query_use_socket else omit }}" login_unix_socket: "{{ pdns_pgsql_unix_socket if pdns_pgsql_query_use_socket else omit }}" query: >- SELECT COUNT(DISTINCT tablename) AS count FROM pg_catalog.pg_tables WHERE schemaname = 'public'; when: - pdns_pgsql_schema_load - item.key.split(':')[0] == 'gpgsql' with_dict: "{{ pdns_backends }}" register: _pdns_check_pgsql_db no_log: "{{ not pdns_verbose }}" changed_when: false - name: Determine location of the PostgreSQL schema SQL file ansible.builtin.shell: cmd: | for p in \ /usr/share/doc/pdns-backend-postgresql-{{ _pdns_running_version }}/schema.pgsql.sql \ /usr/share/doc/pdns-backend-pgsql-{{ _pdns_running_version }}/schema.pgsql.sql \ /usr/share/doc/pdns-backend-postgresql/schema.pgsql.sql \ /usr/share/doc/pdns-backend-pgsql/schema.pgsql.sql \ /usr/share/pdns-backend-pgsql/schema/schema.pgsql.sql \ /usr/share/dbconfig-common/data/pdns-backend-pgsql/install/pgsql \ /usr/share/doc/powerdns/schema.pgsql.sql \ /usr/share/doc/pdns/schema.pgsql.sql; do if [ -f "$p" ]; then echo "$p" exit 0 fi done echo "Can't determine path to PostgreSQL schema" >&2 exit 1 changed_when: false register: _pdns_pgsql_schema_file_detected when: - pdns_pgsql_schema_load - pdns_pgsql_schema_file | length == 0 - name: Set the PostgreSQL schema file variable ansible.builtin.set_fact: _pdns_pgsql_schema_file_to_use: >- {{ _pdns_pgsql_schema_file_detected.stdout if pdns_pgsql_schema_file | length == 0 else pdns_pgsql_schema_file }} when: pdns_pgsql_schema_load - name: Import the PowerDNS PostgreSQL schema community.postgresql.postgresql_db: login_user: "{{ item['item']['value']['user'] }}" login_password: "{{ item['item']['value']['password'] }}" login_host: "{{ item['item']['value']['host'] | default('localhost') if not pdns_pgsql_query_use_socket else omit }}" login_port: "{{ item['item']['value']['port'] | default('5432') if not pdns_pgsql_query_use_socket else omit }}" login_unix_socket: "{{ pdns_pgsql_unix_socket if pdns_pgsql_query_use_socket else omit }}" name: "{{ item['item']['value']['dbname'] }}" state: restore target: "{{ _pdns_pgsql_schema_file_to_use }}" run_once: "{{ pdns_pgsql_schema_on_first_node_only }}" throttle: 1 no_log: "{{ not pdns_verbose }}" when: - pdns_pgsql_schema_load - item['item']['key'].split(':')[0] == 'gpgsql' - item['query_result'][0]['count'] | int == 0 with_items: "{{ _pdns_check_pgsql_db['results'] }}" ================================================ FILE: tasks/database-sqlite3.yml ================================================ --- - name: Install the SQLite dependencies on RedHat ansible.builtin.package: name: sqlite state: "{{ pdns_sqlite_package_state }}" when: ansible_os_family == 'RedHat' tags: - install - name: Install the SQLite dependencies on Debian ansible.builtin.package: name: sqlite3 state: "{{ pdns_sqlite_package_state }}" when: ansible_os_family == 'Debian' tags: - install - config - name: Manage the PowerDNS SQLite databases when: - pdns_package_state != 'absent' - pdns_sqlite_databases_locations | length > 0 tags: - config block: - name: Ensure that the directories containing the PowerDNS SQLite databases exist ansible.builtin.file: name: "{{ item | dirname }}" owner: "{{ pdns_user }}" group: "{{ pdns_group }}" state: directory mode: "0750" with_items: "{{ pdns_sqlite_databases_locations }}" - name: Determine location of the SQL file ansible.builtin.shell: cmd: | for p in \ /usr/share/doc/pdns-backend-sqlite-{{ _pdns_running_version }}/schema.sql \ /usr/share/doc/pdns-backend-sqlite-{{ _pdns_running_version }}/schema.sqlite3.sql \ /usr/share/doc/pdns/schema.sqlite3.sql \ /usr/share/doc/pdns-backend-sqlite3/schema.sqlite3.sql \ /usr/share/doc/pdns-backend-sqlite/schema.sqlite3.sql \ /usr/share/doc/powerdns/schema.sqlite3.sql \ /usr/share/pdns/schema.sqlite3.sql \ /usr/share/powerdns/schema.sqlite3.sql \ /usr/share/pdns-backend-sqlite3/schema/schema.sqlite3.sql \ /usr/share/pdns-backend-sqlite/schema/schema.sqlite3.sql \ /usr/share/doc/pdns/schema.sqlite3.sql.gz \ /usr/share/doc/pdns/schema.sqlite3.sql.xz \ /usr/share/doc/powerdns/schema.sqlite3.sql.gz \ /usr/share/doc/powerdns/schema.sqlite3.sql.xz; do if [ -f "$p" ]; then echo "$p" exit 0 fi done # Fallback for distribution-specific schema locations. schema_file="$(find /usr/share/doc /usr/share -maxdepth 6 -type f \ \( -name "schema.sqlite3.sql" -o -name "schema.sqlite3.sql.gz" -o -name "schema.sqlite3.sql.xz" \) \ -print -quit 2>/dev/null)" if [ -n "$schema_file" ]; then echo "$schema_file" exit 0 fi echo "Can't determine path to SQLite schema">&2 exit 1 changed_when: false register: _pdns_sqlite_schema_file_detected when: pdns_sqlite_schema_file | length == 0 - name: Set the schema file variable ansible.builtin.set_fact: _pdns_sqlite_schema_file_to_use: >- {{ _pdns_sqlite_schema_file_detected.stdout if pdns_sqlite_schema_file | length == 0 else pdns_sqlite_schema_file }} - name: Create the PowerDNS SQLite databases ansible.builtin.shell: cmd: | tmp_schema="$(mktemp)" trap 'rm -f "$tmp_schema"' EXIT case "{{ _pdns_sqlite_schema_file_to_use }}" in *.gz) gzip -dc "{{ _pdns_sqlite_schema_file_to_use }}" > "$tmp_schema" ;; *.xz) xz -dc "{{ _pdns_sqlite_schema_file_to_use }}" > "$tmp_schema" ;; *) cp "{{ _pdns_sqlite_schema_file_to_use }}" "$tmp_schema" ;; esac sqlite3 "{{ item }}" < "$tmp_schema" args: creates: "{{ item }}" with_items: "{{ pdns_sqlite_databases_locations }}" - name: Check the PowerDNS SQLite databases permissions ansible.builtin.file: name: "{{ item }}" owner: "{{ pdns_user }}" group: "{{ pdns_group }}" mode: "0640" state: file with_items: "{{ pdns_sqlite_databases_locations }}" ================================================ FILE: tasks/inspect.yml ================================================ --- - name: Obtain the version of the running PowerDNS instance ansible.builtin.command: pdns_server --version register: _pdns_version_raw check_mode: false changed_when: false failed_when: false tags: - config - name: Extract the PowerDNS version from command output ansible.builtin.set_fact: _pdns_version: >- {{ (_pdns_version_raw.stdout ~ ' ' ~ _pdns_version_raw.stderr) | regex_search('[0-9]+\.[0-9]+\.[0-9]+(?:[-._a-zA-Z0-9]+)?') | default('') }} tags: - config - name: Ensure PowerDNS version was detected ansible.builtin.assert: that: - _pdns_version | length > 0 fail_msg: >- Could not parse PowerDNS version from: stdout='{{ _pdns_version_raw.stdout }}' stderr='{{ _pdns_version_raw.stderr }}' tags: - config - name: Export the running PowerDNS instance version to a variable ansible.builtin.set_fact: _pdns_running_version: "{{ _pdns_version | regex_replace('-[.\\d\\w]+$', '') }}" tags: - config ================================================ FILE: tasks/install.yml ================================================ --- - name: Set up version separator when: pdns_package_version | length > 0 tags: - install block: - name: Prefix the PowerDNS version with the correct separator on RedHat ansible.builtin.set_fact: _pdns_package_version: "-{{ pdns_package_version }}" when: ansible_os_family == 'RedHat' - name: Prefix the PowerDNS version with the correct separator on Debian ansible.builtin.set_fact: _pdns_package_version: "={{ pdns_package_version }}" when: ansible_os_family == 'Debian' - name: Install PowerDNS ansible.builtin.package: name: >- {{ pdns_package_name }}{{ _pdns_package_version | default('') if pdns_package_state != 'absent' else '' }} state: "{{ pdns_package_state }}" notify: reload systemd tags: - install - name: Install PowerDNS debug symbols ansible.builtin.package: name: >- {{ pdns_debug_symbols_package_name }}{{ _pdns_package_version | default('') if pdns_debug_symbols_package_state != 'absent' else '' }} state: "{{ pdns_debug_symbols_package_state }}" when: - pdns_install_debug_symbols_package | bool or pdns_debug_symbols_package_state == 'absent' tags: - install - name: Install PowerDNS backends ansible.builtin.package: name: >- {{ pdns_backends_packages[item.key.split(':')[0]] }}{{ _pdns_package_version | default('') if pdns_backends_packages_state != 'absent' else '' }} state: "{{ pdns_backends_packages_state }}" when: pdns_backends_packages[item.key.split(':')[0]] is defined with_dict: "{{ pdns_backends }}" loop_control: label: "{{ item.key }}" tags: - install ================================================ FILE: tasks/main.yml ================================================ --- - name: Include OS-specific variables (generic to specific) ansible.builtin.include_vars: "{{ role_path }}/vars/{{ item }}" loop: - "{{ ansible_os_family }}.yml" - "{{ ansible_distribution }}.yml" - "{{ ansible_os_family }}-{{ ansible_distribution_major_version }}.yml" - "{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml" when: - lookup('ansible.builtin.fileglob', role_path ~ '/vars/' ~ item, wantlist=True) | length > 0 tags: - always - name: Setup repository ansible.builtin.include_tasks: "repo-{{ ansible_os_family }}.yml" when: "pdns_install_repo | length > 0" tags: - install - repository - name: Install PowerDNS ansible.builtin.include_tasks: install.yml tags: - install - name: Get version of PowerDNS instance ansible.builtin.include_tasks: inspect.yml when: pdns_package_state != 'absent' tags: - db - mysql - pgsql - sqlite - config - name: Configure SELinux ansible.builtin.include_tasks: selinux.yml when: - pdns_package_state != 'absent' - pdns_manage_selinux | bool - ansible_selinux is defined - ansible_selinux.status == 'enabled' tags: - selinux - config - name: Install and configure MySQL database ansible.builtin.include_tasks: database-mysql.yml when: - >- ( pdns_package_state != 'absent' and pdns_mysql_manage_database | bool ) or pdns_mysql_packages_state == 'absent' - >- (pdns_backends | dict2items | selectattr('key', 'match', '^gmysql(:.*)?$') | list | length) > 0 tags: - install - config - db - mysql - name: Install and configure PostgreSQL database ansible.builtin.include_tasks: database-pgsql.yml when: - >- ( pdns_package_state != 'absent' and pdns_pgsql_manage_database | bool ) or pdns_pgsql_packages_state == 'absent' - >- (pdns_backends | dict2items | selectattr('key', 'match', '^gpgsql(:.*)?$') | list | length) > 0 tags: - install - config - db - pgsql - name: Install and configure SQlite database ansible.builtin.include_tasks: database-sqlite3.yml when: - >- ( pdns_package_state != 'absent' and pdns_sqlite_databases_locations | length > 0 ) or pdns_sqlite_package_state == 'absent' tags: - install - config - db - sqlite - name: Install and configure LMDB database ansible.builtin.include_tasks: database-lmdb.yml when: - pdns_package_state != 'absent' - pdns_lmdb_databases_locations | length > 0 tags: - config - db - lmdb - name: Build config file ansible.builtin.include_tasks: configure.yml when: pdns_package_state != 'absent' tags: - config - name: Start and enable the PowerDNS service (systemd) throttle: 1 ansible.builtin.systemd: name: "{{ pdns_service_name }}" state: "{{ pdns_service_state }}" enabled: "{{ pdns_service_enabled }}" masked: "{{ pdns_service_masked }}" when: pdns_package_state != 'absent' tags: - service ================================================ FILE: tasks/repo-Debian.yml ================================================ --- - name: Check if Deb822 repository format is supported by the current distro ansible.builtin.set_fact: _pdns_deb822_supported: >- {{ (ansible_distribution == 'Ubuntu' and (ansible_distribution_major_version | int) >= 22) or (ansible_distribution == 'Debian' and (ansible_distribution_major_version | int) >= 11) }} tags: - install - repository - name: Configure the PowerDNS APT Repository (Deb822-style) when: - (pdns_install_repo['apt_version'] | default('')) | length > 0 - _pdns_deb822_supported tags: - install - repository block: - name: Install python3-debian (required by deb822_repository) ansible.builtin.package: name: python3-debian state: present - name: Add the PowerDNS APT Repository (Deb822-style) ansible.builtin.deb822_repository: name: "{{ pdns_install_repo['name'] }}" types: deb uris: "https://{{ pdns_install_repo['apt_repo_origin'] }}/{{ ansible_distribution | lower }}/" suites: "{{ ansible_distribution_release | lower }}-{{ pdns_install_repo['apt_version'] }}" components: main architectures: "{{ pdns_apt_repo_arch }}" signed_by: "{{ pdns_install_repo['gpg_key'] }}" notify: update the apt cache - name: Remove the legacy PowerDNS APT .list file when using Deb822 ansible.builtin.file: path: "/etc/apt/sources.list.d/{{ pdns_install_repo['name'] }}.list" state: absent notify: update the apt cache - name: Configure the PowerDNS APT Repository (legacy format) when: >- ((pdns_install_repo['apt_version'] | default('')) | length == 0) or (not _pdns_deb822_supported) tags: - install - repository block: - name: Install gnupg ansible.builtin.package: name: gnupg state: present - name: Check if apt-key is available ansible.builtin.stat: path: /usr/bin/apt-key register: _pdns_apt_key_cmd - name: Import the PowerDNS APT Repository key from URL ansible.builtin.apt_key: url: "{{ pdns_install_repo['gpg_key'] }}" id: "{{ pdns_install_repo['gpg_key_id'] | default('') }}" state: present when: - _pdns_apt_key_cmd.stat.exists - pdns_install_repo['gpg_key'] is regex("^[a-z]{3,}://") - name: Import the PowerDNS APT Repository key from File ansible.builtin.apt_key: data: "{{ lookup('file', pdns_install_repo['gpg_key']) }}" id: "{{ pdns_install_repo['gpg_key_id'] | default('') }}" state: present when: - _pdns_apt_key_cmd.stat.exists - not pdns_install_repo['gpg_key'] is regex("^[a-z]{3,}://") - name: Import the PowerDNS APT Repository key from URL (without apt-key) ansible.builtin.get_url: url: "{{ pdns_install_repo['gpg_key'] }}" dest: "/etc/apt/trusted.gpg.d/{{ pdns_install_repo['name'] }}.asc" owner: root group: root mode: "0644" when: - not _pdns_apt_key_cmd.stat.exists - pdns_install_repo['gpg_key'] is regex("^[a-z]{3,}://") - name: Import the PowerDNS APT Repository key from File (without apt-key) ansible.builtin.copy: content: "{{ lookup('file', pdns_install_repo['gpg_key']) }}" dest: "/etc/apt/trusted.gpg.d/{{ pdns_install_repo['name'] }}.asc" owner: root group: root mode: "0644" when: - not _pdns_apt_key_cmd.stat.exists - not pdns_install_repo['gpg_key'] is regex("^[a-z]{3,}://") - name: Add the PowerDNS APT Repository (legacy format) ansible.builtin.apt_repository: filename: "{{ pdns_install_repo['name'] }}" repo: "{{ pdns_install_repo['apt_repo'] }}" state: present notify: update the apt cache - name: Remove the Deb822 PowerDNS APT .sources file when using legacy format ansible.builtin.file: path: "/etc/apt/sources.list.d/{{ pdns_install_repo['name'] }}.sources" state: absent notify: update the apt cache - name: Pin the PowerDNS APT Repository ansible.builtin.template: src: pdns.pin.j2 dest: /etc/apt/preferences.d/pdns owner: root group: root mode: "0644" tags: - install - repository - name: Flush handlers ansible.builtin.meta: flush_handlers tags: - install - repository ================================================ FILE: tasks/repo-RedHat.yml ================================================ --- - name: Install EPEL repositories on RedHat-family distributions when: pdns_install_epel tags: - install - repository block: - name: Install epel-release on CentOS ansible.builtin.package: name: epel-release state: present when: ansible_distribution in [ 'CentOS', 'Rocky', 'AlmaLinux' ] - name: Install epel-release on RHEL ansible.builtin.package: name: "https://dl.fedoraproject.org/pub/epel/epel-release-latest-{{ ansible_distribution_major_version }}.noarch.rpm" state: present when: ansible_distribution in [ 'RedHat' ] - name: Install epel-release on OracleLinux ansible.builtin.package: name: - "oracle-epel-release-el{{ ansible_distribution_major_version }}" state: present when: ansible_distribution in [ 'OracleLinux' ] - name: Install yum-plugin-priorities ansible.builtin.package: name: yum-plugin-priorities state: present when: - ansible_distribution in [ 'CentOS', 'Rocky', 'AlmaLinux' ] - ansible_distribution_major_version | int < 8 tags: - install - repository - name: Install policycoreutils-python-utils to manage an SELinux environment. ansible.builtin.package: name: policycoreutils-python-utils state: present when: - ansible_distribution in [ 'RedHat', 'CentOS', 'Rocky', 'AlmaLinux', 'OracleLinux' ] - ansible_distribution_major_version | int >= 8 tags: - install - repository - name: Add the PowerDNS YUM Repository ansible.builtin.yum_repository: name: "{{ pdns_install_repo['name'] }}" file: "{{ pdns_install_repo['name'] }}" description: PowerDNS Authoritative Server baseurl: "{{ pdns_install_repo['yum_repo_baseurl'] }}" gpgkey: "{{ pdns_install_repo['gpg_key'] }}" gpgcheck: true priority: "90" state: present tags: - install - repository - name: Add the PowerDNS debug symbols YUM Repository ansible.builtin.yum_repository: name: "{{ pdns_install_repo['name'] }}-debuginfo" file: "{{ pdns_install_repo['name'] }}" description: PowerDNS Authoritative Server - debug symbols baseurl: "{{ pdns_install_repo['yum_debug_symbols_repo_baseurl'] }}" gpgkey: "{{ pdns_install_repo['gpg_key'] }}" gpgcheck: true priority: "90" state: present when: pdns_install_debug_symbols_package tags: - install - repository ================================================ FILE: tasks/selinux.yml ================================================ --- - name: Allow mysql connect from pdns in selinux ansible.posix.seboolean: name: pdns_can_network_connect_db state: true persistent: true when: >- (pdns_backends | dict2items | selectattr('key', 'search', '^g(mysql|pgsql)(:.*)?$') | list | length) > 0 tags: - config - name: Allow pdns to bind to udp high ports community.general.seport: ports: 10000-20000 proto: udp setype: dns_port_t state: present tags: - config ================================================ FILE: templates/override-service.systemd.conf.j2 ================================================ [Service] {% for k, v in pdns_service_overrides.items() %} {% if k == 'ExecStart' %}ExecStart= {% elif k == 'ExecStartPre' %}ExecStartPre= {% endif %} {{ k }}={{ v }} {% endfor %} ================================================ FILE: templates/pdns.conf.j2 ================================================ config-dir={{ pdns_config_dir }} setuid={{ pdns_user }} setgid={{ pdns_group }} {% for config_item, value in pdns_config.items() | sort() %} {% if config_item not in ["config-dir", "launch", "setuid", "setgid"] %} {% if value is sameas True %} {{ config_item }}=yes {% elif value is sameas False %} {{ config_item }}=no {% elif value == None %} {{ config_item }}= {% elif value is string %} {{ config_item }}={{ value | string }} {% elif value is sequence %} {{ config_item }}={{ value | join(',') }} {% else %} {{ config_item }}={{ value | string }} {% endif %} {% endif %} {% endfor %} launch= {% for backend in pdns_backends | sort() -%} launch+={{ backend }} {% set backend_string = backend | replace(':', '-') %} {% for backend_item, value in pdns_backends[backend].items() | sort() -%} {% if value is sameas True %} {{ backend_string }}-{{ backend_item }}=yes {% elif value is sameas False %} {{ backend_string }}-{{ backend_item }}=no {% elif value == None %} {{ backend_string }}-{{ backend_item }}= {% else %} {{ backend_string }}-{{ backend_item }}={{ value | string }} {% endif %} {% endfor %} {% endfor -%} ================================================ FILE: templates/pdns.pin.j2 ================================================ Package: pdns-* Pin: origin {{ pdns_install_repo['apt_repo_origin'] }} Pin-Priority: 600 ================================================ FILE: test-requirements.txt ================================================ ansible-lint==24.12.2 ansible-compat==24.10.0 yamllint==1.38.0 molecule-plugins[docker]==23.6.0 molecule-plugins[lint]==23.6.0 molecule==24.9.0 pytest-testinfra==10.1.1 docker==7.1.0 ================================================ FILE: tox.ini ================================================ [tox] minversion = 1.8 envlist = ansible{215,216} skipsdist = true [gh-actions:env] ANSIBLE= 2.15: ansible215 2.16: ansible216 [testenv] passenv = * deps = -rtest-requirements.txt ansible215: ansible-core>2.15,<2.16 ansible216: ansible-core>2.16,<2.17 setenv = PY_COLORS = 1 commands = {posargs:molecule test --all --destroy always} ================================================ FILE: vars/Archlinux.yml ================================================ --- # The name of the PowerDNS package default_pdns_package_name: "powerdns" # List of PowerDNS Backends packages. Arch ships all backends in the main package default_pdns_backends_packages: {} # The directory where the PowerDNS configuration is located default_pdns_config_dir: '/etc/powerdns' # Use MariaDB client for MySQL/MariaDB schema checks/import default_pdns_backends_mysql_cmd: "mariadb" # Additional MariaDB CLI arguments used for schema checks/import default_pdns_mysql_cli_extra_args: "--skip-ssl-verify-server-cert" # Packages to install for MySQL support default_pdns_mysql_packages: - python-pymysql - python-cryptography - mariadb-clients # Packages to install for PostgreSQL support default_pdns_pgsql_packages: - python-psycopg2 - postgresql # Other defaults pdns_user: powerdns pdns_group: powerdns ================================================ FILE: vars/Debian.yml ================================================ --- # The name of the PowerDNS Authoritative Server package default_pdns_package_name: "pdns-server" # The name of the PowerDNS Authoritative Server debug package default_pdns_debug_symbols_package_name: "pdns-server-dbg" # Packages needed to install MySQL default_pdns_mysql_packages: - default-mysql-client - python3-mysqldb - python3-cryptography # The command used for MySQL/MariaDB schema checks/import default_pdns_backends_mysql_cmd: "mariadb" default_pdns_mysql_cli_extra_args: "" # Packages needed to install PostgreSQL default_pdns_pgsql_packages: - postgresql-client - python3-psycopg2 # List of PowerDNS Authoritative Server Backends packages on Debian default_pdns_backends_packages: geo: pdns-backend-geo geoip: pdns-backend-geoip gmysql: pdns-backend-mysql gpgsql: pdns-backend-pgsql gsqlite3: pdns-backend-sqlite3 ldap: pdns-backend-ldap lmdb: pdns-backend-lmdb lua: pdns-backend-lua mydns: pdns-backend-mydns pipe: pdns-backend-pipe remote: pdns-backend-remote tinydns: pdns-backend-tinydns # The directory where the PowerDNS Authoritative Server configuration is located default_pdns_config_dir: "/etc/powerdns" ================================================ FILE: vars/RedHat.yml ================================================ --- # The name of the PowerDNS Authoritative Server package default_pdns_package_name: "pdns" # Packages needed to install MySQL default_pdns_mysql_packages: - mariadb - mariadb-server - mariadb-connector-c - python3-PyMySQL - python3-cryptography - perl-DBD-MySQL # The command used for MySQL/MariaDB schema checks/import default_pdns_backends_mysql_cmd: "mariadb" # Additional MariaDB CLI arguments used for schema checks/import default_pdns_mysql_cli_extra_args: "" # Packages needed to install PostgreSQL default_pdns_pgsql_packages: - postgresql - python3-psycopg2 # The name of the PowerDNS Authoritative Server debug package default_pdns_debug_symbols_package_name: "pdns-debuginfo" # List of PowerDNS Authoritative Server backends packages on RedHat default_pdns_backends_packages: geo: pdns-backend-geo geoip: pdns-backend-geoip gmysql: pdns-backend-mysql gpgsql: pdns-backend-postgresql gsqlite3: pdns-backend-sqlite ldap: pdns-backend-ldap lmdb: pdns-backend-lmdb lua: pdns-backend-lua mydns: pdns-backend-mydns pipe: pdns-backend-pipe remote: pdns-backend-remote tinydns: pdns-backend-tinydns # The directory where the PowerDNS Authoritative Server configuration is located default_pdns_config_dir: "/etc/pdns" ================================================ FILE: vars/Ubuntu-20.yml ================================================ --- # Ubuntu 20 uses PyMySQL for Ansible MySQL modules. default_pdns_mysql_packages: - default-mysql-client - python3-pymysql - python3-cryptography ================================================ FILE: vars/main.yml ================================================ --- pdns_apt_repo_arch_map: x86_64: amd64 amd64: amd64 aarch64: arm64 arm64: arm64 pdns_apt_repo_arch: >- {{ pdns_apt_repo_arch_map.get((ansible_architecture | default('amd64')) | lower, (ansible_architecture | default('amd64')) | lower) }} pdns_auth_powerdns_repo_master: apt_repo_origin: "repo.powerdns.com" apt_version: "auth-master" apt_repo: >- deb [arch={{ pdns_apt_repo_arch }}] http://repo.powerdns.com/{{ ansible_distribution | lower }} {{ ansible_distribution_release | lower }}-auth-master main gpg_key: "http://repo.powerdns.com/CBC8B383-pub.asc" gpg_key_id: "D47975F8DAE32700A563E64FFF389421CBC8B383" yum_repo_baseurl: "http://repo.powerdns.com/centos/$basearch/$releasever/auth-master" yum_debug_symbols_repo_baseurl: "http://repo.powerdns.com/centos/$basearch/$releasever/auth-master/debug" name: "powerdns-auth-master" pdns_auth_powerdns_repo_48: apt_repo_origin: "repo.powerdns.com" apt_version: "auth-48" apt_repo: >- deb [arch={{ pdns_apt_repo_arch }}] http://repo.powerdns.com/{{ ansible_distribution | lower }} {{ ansible_distribution_release | lower }}-auth-48 main gpg_key: "http://repo.powerdns.com/FD380FBB-pub.asc" gpg_key_id: "9FAAA5577E8FCF62093D036C1B0C6205FD380FBB" yum_repo_baseurl: "http://repo.powerdns.com/centos/$basearch/$releasever/auth-48" yum_debug_symbols_repo_baseurl: "http://repo.powerdns.com/centos/$basearch/$releasever/auth-48/debug" name: "powerdns-auth-48" pdns_auth_powerdns_repo_49: apt_repo_origin: "repo.powerdns.com" apt_version: "auth-49" apt_repo: >- deb [arch={{ pdns_apt_repo_arch }}] http://repo.powerdns.com/{{ ansible_distribution | lower }} {{ ansible_distribution_release | lower }}-auth-49 main gpg_key: "http://repo.powerdns.com/FD380FBB-pub.asc" gpg_key_id: "9FAAA5577E8FCF62093D036C1B0C6205FD380FBB" yum_repo_baseurl: "http://repo.powerdns.com/centos/$basearch/$releasever/auth-49" yum_debug_symbols_repo_baseurl: "http://repo.powerdns.com/centos/$basearch/$releasever/auth-49/debug" name: "powerdns-auth-49" pdns_auth_powerdns_repo_50: apt_repo_origin: "repo.powerdns.com" apt_version: "auth-50" apt_repo: >- deb [arch={{ pdns_apt_repo_arch }}] http://repo.powerdns.com/{{ ansible_distribution | lower }} {{ ansible_distribution_release | lower }}-auth-50 main gpg_key: "http://repo.powerdns.com/FD380FBB-pub.asc" gpg_key_id: "9FAAA5577E8FCF62093D036C1B0C6205FD380FBB" yum_repo_baseurl: "http://repo.powerdns.com/centos/$basearch/$releasever/auth-50" yum_debug_symbols_repo_baseurl: "http://repo.powerdns.com/centos/$basearch/$releasever/auth-50/debug" name: "powerdns-auth-50" default_pdns_service_overrides: User: "{{ pdns_user }}" Group: "{{ pdns_group }}"