Showing preview only (201K chars total). Download the full file or copy to clipboard to get everything.
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
[](https://github.com/PowerDNS/pdns-ansible)
[](https://opensource.org/licenses/MIT)
[](https://galaxy.ansible.com/PowerDNS/pdns)
[](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. <br />
**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. <br />
**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 }}"
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
SYMBOL INDEX (72 symbols across 15 files) FILE: molecule/resources/tests/all/test_common.py function test_distribution (line 7) | def test_distribution(host): function test_package (line 12) | def test_package(host): function test_service (line 28) | def test_service(host): FILE: molecule/resources/tests/backend-bind/test_backend_bind.py function _pdns_config_dir (line 6) | def _pdns_config_dir(host): function _bind_config_file (line 12) | def _bind_config_file(host): function test_config (line 20) | def test_config(host): function test_bind_configuration_files (line 29) | def test_bind_configuration_files(host): function test_bind_instance_service_is_active (line 43) | def test_bind_instance_service_is_active(host): FILE: molecule/resources/tests/backend-lmdb/test_backend_lmdb.py function _pdns_config_dir (line 6) | def _pdns_config_dir(host): function _lmdb_config_file (line 12) | def _lmdb_config_file(host): function test_package (line 20) | def test_package(host): function test_config (line 26) | def test_config(host): function test_lmdb_instance_service_is_active (line 35) | def test_lmdb_instance_service_is_active(host): FILE: molecule/resources/tests/backend-mariadb/test_backend_mariadb.py function _pdns_config_dir (line 6) | def _pdns_config_dir(host): function _mariadb_config_file (line 12) | def _mariadb_config_file(host): function test_package (line 20) | def test_package(host): function test_config (line 26) | def test_config(host): FILE: molecule/resources/tests/backend-mysql/test_backend_mysql.py function _pdns_config_dir (line 6) | def _pdns_config_dir(host): function _mysql_config_file (line 12) | def _mysql_config_file(host): function test_package (line 20) | def test_package(host): function test_config (line 26) | def test_config(host): FILE: molecule/resources/tests/backend-postgresql/test_backend_postgresql.py function _pdns_config_dir (line 6) | def _pdns_config_dir(host): function _postgresql_config_file (line 12) | def _postgresql_config_file(host): function test_package (line 20) | def test_package(host): function test_config (line 30) | def test_config(host): function test_postgresql_instance_service_is_active (line 43) | def test_postgresql_instance_service_is_active(host): FILE: molecule/resources/tests/backend-sqlite/test_backend_sqlite.py function _pdns_config_dir (line 6) | def _pdns_config_dir(host): function _sqlite_config_file (line 12) | def _sqlite_config_file(host): function test_package (line 20) | def test_package(host): function test_config (line 30) | def test_config(host): function test_database_exists (line 38) | def test_database_exists(host): FILE: molecule/resources/tests/backend-zones/test_backend_zones.py function _normalize_zone (line 1) | def _normalize_zone(zone): function _dns_lookup_rcode (line 5) | def _dns_lookup_rcode(host, zone, port): function _pdnsutil_command (line 20) | def _pdnsutil_command(subcommand, zone=None, config_name=''): function test_backend_zones_are_listed (line 30) | def test_backend_zones_are_listed(host): function test_backend_zones_are_queryable (line 50) | def test_backend_zones_are_queryable(host): function test_backend_zones_dns_lookup_noerror (line 65) | def test_backend_zones_dns_lookup_noerror(host): FILE: molecule/resources/tests/repo-48/test_repo_48.py function _release_major (line 7) | def _release_major(host): function _supports_deb822 (line 13) | def _supports_deb822(host): function _assert_debian_repo_layout (line 23) | def _assert_debian_repo_layout(host): function _repo_file (line 39) | def _repo_file(host): function test_repo_file (line 50) | def test_repo_file(host): function test_pdns_repo (line 59) | def test_pdns_repo(host): function test_repo_pinning_file (line 66) | def test_repo_pinning_file(host): function test_pdns_version (line 77) | def test_pdns_version(host): FILE: molecule/resources/tests/repo-49/test_repo_49.py function _release_major (line 7) | def _release_major(host): function _supports_deb822 (line 13) | def _supports_deb822(host): function _assert_debian_repo_layout (line 23) | def _assert_debian_repo_layout(host): function _repo_file (line 39) | def _repo_file(host): function test_repo_file (line 50) | def test_repo_file(host): function test_pdns_repo (line 59) | def test_pdns_repo(host): function test_repo_pinning_file (line 66) | def test_repo_pinning_file(host): function test_pdns_version (line 77) | def test_pdns_version(host): FILE: molecule/resources/tests/repo-50/test_repo_50.py function _release_major (line 7) | def _release_major(host): function _supports_deb822 (line 13) | def _supports_deb822(host): function _assert_debian_repo_layout (line 23) | def _assert_debian_repo_layout(host): function _repo_file (line 39) | def _repo_file(host): function test_repo_file (line 50) | def test_repo_file(host): function test_pdns_repo (line 59) | def test_pdns_repo(host): function test_repo_pinning_file (line 66) | def test_repo_pinning_file(host): function test_pdns_version (line 77) | def test_pdns_version(host): FILE: molecule/resources/tests/repo-master/test_repo_master.py function _release_major (line 7) | def _release_major(host): function _supports_deb822 (line 13) | def _supports_deb822(host): function _assert_debian_repo_layout (line 23) | def _assert_debian_repo_layout(host): function _repo_file (line 39) | def _repo_file(host): function test_repo_file (line 50) | def test_repo_file(host): function test_pdns_repo (line 59) | def test_pdns_repo(host): function test_repo_pinning_file (line 66) | def test_repo_pinning_file(host): function test_pdns_version (line 77) | def test_pdns_version(host): FILE: molecule/resources/tests/service-mask/test_service_mask.py function test_default_pdns_service_is_masked_and_stopped (line 1) | def test_default_pdns_service_is_masked_and_stopped(host): FILE: molecule/resources/tests/systemd-no-override/test_override.py function test_systemd_override (line 1) | def test_systemd_override(host): FILE: molecule/resources/tests/systemd-override/test_override.py function test_systemd_override (line 1) | def test_systemd_override(host):
Condensed preview — 79 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (198K chars).
[
{
"path": ".ansible-lint",
"chars": 19,
"preview": "---\n\nskip_list: []\n"
},
{
"path": ".github/dependabot.yml",
"chars": 435,
"preview": "---\n# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates\n\nversion: 2"
},
{
"path": ".github/workflows/main.yml",
"chars": 1006,
"preview": "---\non:\n push:\n pull_request:\n schedule:\n - cron: '33 5 * * 0'\n\njobs:\n Lint:\n runs-on: ubuntu-22.04\n steps:"
},
{
"path": ".gitignore",
"chars": 214,
"preview": "### Ansible ###\n*.retry\n.ansible_cache\n.ansible\n\n### Python ###\n# Byte-compiled / optimized / DLL files\n.pytest_cache/\n_"
},
{
"path": ".yamllint",
"chars": 821,
"preview": "---\n# Based on ansible-lint config\nextends: default\n\nignore: |\n .tox/\n .git/\n .venv/\n venv/\n .cache/\n .pytest_cach"
},
{
"path": "CHANGELOG.md",
"chars": 14055,
"preview": "## v1.10.0 (2026-02-24)\n\nNEW FEATURES:\n- Add role-level package state controls for PowerDNS, debug symbols, backend pack"
},
{
"path": "LICENSE",
"chars": 1072,
"preview": "MIT License\n\nCopyright (c) 2017 PowerDNS.COM BV\n\nPermission is hereby granted, free of charge, to any person obtaining a"
},
{
"path": "README.md",
"chars": 16366,
"preview": "# Ansible Role: PowerDNS Authoritative Server\n\n[:\n return zone.rstrip('.')\n\n\ndef _dns_lookup_rcode(host, zone, port):\n script = (\n "
},
{
"path": "molecule/resources/tests/repo-48/test_repo_48.py",
"chars": 2235,
"preview": "import re\n\ndebian_os = ['debian', 'ubuntu']\nrhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux']\n\n\ndef _release_ma"
},
{
"path": "molecule/resources/tests/repo-49/test_repo_49.py",
"chars": 2270,
"preview": "import re\n\ndebian_os = ['debian', 'ubuntu']\nrhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux']\n\n\ndef _release_ma"
},
{
"path": "molecule/resources/tests/repo-50/test_repo_50.py",
"chars": 2270,
"preview": "import re\n\ndebian_os = ['debian', 'ubuntu']\nrhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux']\n\n\ndef _release_ma"
},
{
"path": "molecule/resources/tests/repo-master/test_repo_master.py",
"chars": 2337,
"preview": "import re\n\ndebian_os = ['debian', 'ubuntu']\nrhel_os = ['redhat', 'centos', 'ol', 'rocky', 'almalinux']\n\n\ndef _release_ma"
},
{
"path": "molecule/resources/tests/service-mask/test_service_mask.py",
"chars": 1069,
"preview": "def test_default_pdns_service_is_masked_and_stopped(host):\n smgr = host.ansible(\"setup\")[\"ansible_facts\"][\"ansible_se"
},
{
"path": "molecule/resources/tests/systemd-no-override/test_override.py",
"chars": 257,
"preview": "def test_systemd_override(host):\n smgr = host.ansible(\"setup\")[\"ansible_facts\"][\"ansible_service_mgr\"]\n if smgr =="
},
{
"path": "molecule/resources/tests/systemd-override/test_override.py",
"chars": 591,
"preview": "def test_systemd_override(host):\n smgr = host.ansible(\"setup\")[\"ansible_facts\"][\"ansible_service_mgr\"]\n if smgr =="
},
{
"path": "molecule/resources/vars/molecule.yml",
"chars": 352,
"preview": "---\nmolecule_file: \"{{ lookup('env', 'MOLECULE_FILE') }}\"\nmolecule_ephemeral_directory: \"{{ lookup('env', 'MOLECULE_EPHE"
},
{
"path": "molecule/resources/vars/pdns-backend-bind.yml",
"chars": 906,
"preview": "---\n\n# Bind backend profile\npdns_backends_bind:\n bind:\n config: \"{{ pdns_config_dir }}/named.conf\"\n\npdns_instance:\n "
},
{
"path": "molecule/resources/vars/pdns-backend-lmdb.yml",
"chars": 530,
"preview": "---\n\n# LMDB backend profile\npdns_backends_lmdb:\n lmdb:\n filename: /var/lib/powerdns/pdns.lmdb\n\npdns_instance:\n serv"
},
{
"path": "molecule/resources/vars/pdns-backend-mariadb.yml",
"chars": 1328,
"preview": "---\n\n# MariaDB backend profile\npdns_backends_mariadb:\n 'gmysql:mariadb':\n host: \"mariadb\"\n dbname: \"{{ ansible_ho"
},
{
"path": "molecule/resources/vars/pdns-backend-mysql.yml",
"chars": 1412,
"preview": "---\n\n# MySQL backend profile\npdns_backends_mysql:\n 'gmysql:mysql':\n host: \"mysql\"\n dbname: \"{{ ansible_hostname |"
},
{
"path": "molecule/resources/vars/pdns-backend-postgresql.yml",
"chars": 958,
"preview": "---\n\n# PostgreSQL backend profile\npdns_backends_pgsql:\n gpgsql:\n host: \"postgresql\"\n dbname: \"{{ ansible_hostname"
},
{
"path": "molecule/resources/vars/pdns-backend-sqlite3.yml",
"chars": 588,
"preview": "---\n\n# SQLite3 backend profile\npdns_backends_sqlite3:\n gsqlite3:\n database: /var/lib/powerdns/pdns.sqlite3\n dnsse"
},
{
"path": "molecule/resources/vars/pdns-common.yml",
"chars": 687,
"preview": "---\n\n##\n# PowerDNS Configuration\n##\n\npdns_config_common:\n\n # Turns on primary operations\n primary: true\n\n include-dir"
},
{
"path": "molecule/resources/vars/pdns-no-overrides.yml",
"chars": 350,
"preview": "---\n\n##\n# PowerDNS Configuration\n##\n\npdns_config:\n\n # Turns on primary operations\n primary: true\n\n # Listen Address\n "
},
{
"path": "molecule/resources/vars/pdns-os-repos.yml",
"chars": 513,
"preview": "---\n\n##\n# PowerDNS Configuration\n##\n\n_pdns_config_base:\n\n # Listen Address\n local-address: \"127.0.0.1\"\n local-port: \""
},
{
"path": "molecule/resources/vars/pdns-repo-48.yml",
"chars": 94,
"preview": "---\n\n##\n# PowerDNS 4.8.x Repository\n##\n\npdns_install_repo: \"{{ pdns_auth_powerdns_repo_48 }}\"\n"
},
{
"path": "molecule/resources/vars/pdns-repo-49.yml",
"chars": 94,
"preview": "---\n\n##\n# PowerDNS 4.9.x Repository\n##\n\npdns_install_repo: \"{{ pdns_auth_powerdns_repo_49 }}\"\n"
},
{
"path": "molecule/resources/vars/pdns-repo-50.yml",
"chars": 94,
"preview": "---\n\n##\n# PowerDNS 5.0.x Repository\n##\n\npdns_install_repo: \"{{ pdns_auth_powerdns_repo_50 }}\"\n"
},
{
"path": "molecule/resources/vars/pdns-repo-master.yml",
"chars": 99,
"preview": "---\n\n##\n# PowerDNS Master Repository\n##\n\npdns_install_repo: \"{{ pdns_auth_powerdns_repo_master }}\"\n"
},
{
"path": "requirements.yml",
"chars": 198,
"preview": "---\ncollections:\n - name: community.mysql\n - name: community.postgresql\n - name: community.general\n version: \"<11."
},
{
"path": "tasks/configure.yml",
"chars": 3010,
"preview": "---\n- name: Set up systemd override\n when: ansible_service_mgr == \"systemd\"\n tags:\n - config\n block:\n\n - name: "
},
{
"path": "tasks/database-lmdb.yml",
"chars": 313,
"preview": "---\n\n- name: Ensure that the directories containing the PowerDNS LMDB databases exist\n ansible.builtin.file:\n name: "
},
{
"path": "tasks/database-mysql.yml",
"chars": 6280,
"preview": "---\n\n- name: Install the MySQL dependencies\n ansible.builtin.package:\n name: \"{{ pdns_mysql_packages }}\"\n state: "
},
{
"path": "tasks/database-pgsql.yml",
"chars": 5851,
"preview": "---\n\n- name: Install the PostgreSQL dependencies\n ansible.builtin.package:\n name: \"{{ pdns_pgsql_packages }}\"\n st"
},
{
"path": "tasks/database-sqlite3.yml",
"chars": 3906,
"preview": "---\n\n- name: Install the SQLite dependencies on RedHat\n ansible.builtin.package:\n name: sqlite\n state: \"{{ pdns_s"
},
{
"path": "tasks/inspect.yml",
"chars": 1010,
"preview": "---\n\n- name: Obtain the version of the running PowerDNS instance\n ansible.builtin.command: pdns_server --version\n regi"
},
{
"path": "tasks/install.yml",
"chars": 1658,
"preview": "---\n- name: Set up version separator\n when: pdns_package_version | length > 0\n tags:\n - install\n block:\n - name"
},
{
"path": "tasks/main.yml",
"chars": 3115,
"preview": "---\n\n- name: Include OS-specific variables (generic to specific)\n ansible.builtin.include_vars: \"{{ role_path }}/vars/{"
},
{
"path": "tasks/repo-Debian.yml",
"chars": 4393,
"preview": "---\n- name: Check if Deb822 repository format is supported by the current distro\n ansible.builtin.set_fact:\n _pdns_d"
},
{
"path": "tasks/repo-RedHat.yml",
"chars": 2419,
"preview": "---\n\n- name: Install EPEL repositories on RedHat-family distributions\n when: pdns_install_epel\n tags:\n - install\n "
},
{
"path": "tasks/selinux.yml",
"chars": 484,
"preview": "---\n\n- name: Allow mysql connect from pdns in selinux\n ansible.posix.seboolean:\n name: pdns_can_network_connect_db\n "
},
{
"path": "templates/override-service.systemd.conf.j2",
"chars": 180,
"preview": "[Service]\n{% for k, v in pdns_service_overrides.items() %}\n{% if k == 'ExecStart' %}ExecStart=\n{% elif k == 'ExecStartPr"
},
{
"path": "templates/pdns.conf.j2",
"chars": 1123,
"preview": "config-dir={{ pdns_config_dir }}\nsetuid={{ pdns_user }}\nsetgid={{ pdns_group }}\n{% for config_item, value in pdns_config"
},
{
"path": "templates/pdns.pin.j2",
"chars": 89,
"preview": "Package: pdns-*\nPin: origin {{ pdns_install_repo['apt_repo_origin'] }}\nPin-Priority: 600\n"
},
{
"path": "test-requirements.txt",
"chars": 183,
"preview": "ansible-lint==24.12.2\nansible-compat==24.10.0\nyamllint==1.38.0\nmolecule-plugins[docker]==23.6.0\nmolecule-plugins[lint]=="
},
{
"path": "tox.ini",
"chars": 357,
"preview": "[tox]\nminversion = 1.8\nenvlist = ansible{215,216}\nskipsdist = true\n\n[gh-actions:env]\nANSIBLE=\n 2.15: ansible215\n 2.16:"
},
{
"path": "vars/Archlinux.yml",
"chars": 837,
"preview": "---\n\n# The name of the PowerDNS package\ndefault_pdns_package_name: \"powerdns\"\n\n# List of PowerDNS Backends packages. Arc"
},
{
"path": "vars/Debian.yml",
"chars": 1171,
"preview": "---\n\n# The name of the PowerDNS Authoritative Server package\ndefault_pdns_package_name: \"pdns-server\"\n\n# The name of the"
},
{
"path": "vars/RedHat.yml",
"chars": 1271,
"preview": "---\n\n# The name of the PowerDNS Authoritative Server package\ndefault_pdns_package_name: \"pdns\"\n\n# Packages needed to ins"
},
{
"path": "vars/Ubuntu-20.yml",
"chars": 156,
"preview": "---\n\n# Ubuntu 20 uses PyMySQL for Ansible MySQL modules.\ndefault_pdns_mysql_packages:\n - default-mysql-client\n - pytho"
},
{
"path": "vars/main.yml",
"chars": 2776,
"preview": "---\n\npdns_apt_repo_arch_map:\n x86_64: amd64\n amd64: amd64\n aarch64: arm64\n arm64: arm64\n\npdns_apt_repo_arch: >-\n {{"
}
]
About this extraction
This page contains the full source code of the PowerDNS/pdns-ansible GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 79 files (181.6 KB), approximately 51.6k tokens, and a symbol index with 72 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.