From 98fc26f6e537c9eba67431e6a555eca9d1b4d982 Mon Sep 17 00:00:00 2001 From: Mathias Kaufmann Date: Thu, 23 Feb 2017 00:35:15 +0100 Subject: [PATCH 01/11] Add multi DB support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To support more databases MYSQL_AUTOCONF=true has been renamed to AUTOCONF=mysql. AUTOCONF can be either mysql (default), postgres or sqlite. The configuration flow has been changed a little bit. At first the „well-known“ variables are mapped to 12factor-formatted variables. Then Database-Setup has been extended for postgres and sqlite. At last the pdns.conf will be updated with all given 12factor-formatted environment variables. This may be redundant, as all configuration variables may be provided via command line but enables compact configuration via --envfile docker cmdline argument. --- Dockerfile | 38 +- README.md | 50 ++- entrypoint.sh | 197 ++++++----- pdns.conf | 533 +++++++++++++++++++++++++---- schema.sql => sql/mysql.schema.sql | 0 sql/pgsql.schema.sql | 95 +++++ sql/sqlite3.schema.sql | 92 +++++ 7 files changed, 845 insertions(+), 160 deletions(-) rename schema.sql => sql/mysql.schema.sql (100%) create mode 100644 sql/pgsql.schema.sql create mode 100644 sql/sqlite3.schema.sql diff --git a/Dockerfile b/Dockerfile index fc2ad5f..4464962 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,26 @@ FROM alpine:3.9 -MAINTAINER Christoph Wiechert -ENV POWERDNS_VERSION=4.3.1 \ - MYSQL_DEFAULT_AUTOCONF=true \ - MYSQL_DEFAULT_HOST="mysql" \ - MYSQL_DEFAULT_PORT="3306" \ - MYSQL_DEFAULT_USER="root" \ - MYSQL_DEFAULT_PASS="root" \ - MYSQL_DEFAULT_DB="pdns" +LABEL \ + MAINTAINER="Christoph Wiechert " \ + CONTRIBUTORS="Mathias Kaufmann " -RUN apk --update add bash libpq sqlite-libs libstdc++ libgcc mariadb-client mariadb-connector-c lua-dev curl-dev && \ +ENV REFRESHED_AT="2019-10-10" \ + POWERDNS_VERSION=4.3.1 \ + AUTOCONF=mysql \ + MYSQL_HOST="mysql" \ + MYSQL_PORT="3306" \ + MYSQL_USER="root" \ + MYSQL_PASS="root" \ + MYSQL_DB="pdns" \ + MYSQL_DNSSEC="no" \ + PGSQL_HOST="postgres" \ + PGSQL_PORT="5432" \ + PGSQL_USER="postgres" \ + PGSQL_PASS="postgres" \ + PGSQL_DB="pdns" \ + SQLITE_DB="pdns.sqlite3" + +RUN apk --update add bash libpq sqlite-libs libstdc++ libgcc mariadb-client postgresql-client sqlite mariadb-connector-c lua-dev curl-dev && \ apk add --virtual build-deps \ g++ make mariadb-dev postgresql-dev sqlite-dev curl boost-dev mariadb-connector-c-dev && \ curl -sSL https://downloads.powerdns.com/releases/pdns-$POWERDNS_VERSION.tar.bz2 | tar xj -C /tmp && \ @@ -25,9 +36,10 @@ RUN apk --update add bash libpq sqlite-libs libstdc++ libgcc mariadb-client mari mv /tmp/lib* /usr/lib/ && \ rm -rf /tmp/pdns-$POWERDNS_VERSION /var/cache/apk/* -ADD schema.sql pdns.conf /etc/pdns/ -ADD entrypoint.sh / - EXPOSE 53/tcp 53/udp -ENTRYPOINT ["/entrypoint.sh"] +ADD sql/* pdns.conf /etc/pdns/ + +ADD entrypoint.sh /bin/powerdns + +ENTRYPOINT ["powerdns"] diff --git a/README.md b/README.md index 8ae2f40..a49fddd 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ * Small Alpine based Image * MySQL (default), Postgres, SQLite and Bind backend included * DNSSEC support optional -* Automatic MySQL database initialization +* Automatic database initialization for MySQL, Postgres and SQLite * Latest PowerDNS version (if not pls file an issue) * Guardian process enabled * Graceful shutdown using pdns_control @@ -21,6 +21,8 @@ ## Usage +### MySQL + ```shell # Start a MySQL Container $ docker run -d \ @@ -33,6 +35,7 @@ $ docker run --name pdns \ --link pdns-mysql:mysql \ -p 53:53 \ -p 53:53/udp \ + -e AUTOCONF=mysql -e MYSQL_USER=root \ -e MYSQL_PASS=supersecret \ -e MYSQL_PORT=3306 \ @@ -41,6 +44,40 @@ $ docker run --name pdns \ --allow-axfr-ips=127.0.0.1,123.1.2.3 ``` +### Postgres + +```shell +# Start a Postgres Container +$ docker run -d \ + --name pdns-postgres \ + -e POSTGRES_PASSWORD=supersecret \ + -v $PWD/postgres-data:/var/lib/postgresql \ + postgres:9.6 + +$ docker run --name pdns \ + --link pdns-postgres:postgres \ + -p 53:53 \ + -p 53:53/udp \ + -e AUTOCONF=postgres \ + -e PGSQL_USER=postgres \ + -e PGSQL_PASS=supersecret \ + psitrax/powerdns \ + --cache-ttl=120 \ + --allow-axfr-ips=127.0.0.1,123.1.2.3 +``` + +### SQLite + +```shell +$ docker run --name pdns \ + -p 53:53 \ + -p 53:53/udp \ + -e AUTOCONF=sqlite \ + psitrax/powerdns \ + --cache-ttl=120 \ + --allow-axfr-ips=127.0.0.1,123.1.2.3 +``` + ## Configuration **Environment Configuration:** @@ -51,9 +88,16 @@ $ docker run --name pdns \ * `MYSQL_PASS=root` * `MYSQL_DB=pdns` * `MYSQL_DNSSEC=no` -* To support docker secrets, use same variables as above with suffix `_FILE`. -* Want to disable mysql initialization? Use `MYSQL_AUTOCONF=false` +* Postgres connection settings + * `PGSQL_HOST=mysql` + * `PGSQL_USER=root` + * `PGSQL_PASS=root` + * `PGSQL_DB=pdns` +* SQLite connection settings + * `SQLITE_DB=/pdns.sqlite3` * DNSSEC is disabled by default, to enable use `MYSQL_DNSSEC=yes` +* Want to disable database initialization? Use `AUTOCONF=false` +* Want to apply 12Factor-Pattern? Apply environment variables of the form `PDNS_$pdns-config-variable=$config-value`, like `PDNS_WEBSERVER=yes` * Want to use own config files? Mount a Volume to `/etc/pdns/conf.d` or simply overwrite `/etc/pdns/pdns.conf` **PowerDNS Configuration:** diff --git a/entrypoint.sh b/entrypoint.sh index aa2f7fb..f84b535 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,100 +1,137 @@ #!/bin/bash set -e -# usage: file_env VAR [DEFAULT] -# ie: file_env 'XYZ_DB_PASSWORD' 'example' -# (will allow for "$XYZ_DB_PASSWORD_FILE" to fill in the value of -# "$XYZ_DB_PASSWORD" from a file, especially for Docker's secrets feature) -# source: https://github.com/docker-library/mariadb/blob/master/docker-entrypoint.sh -file_env() { - local var="$1" - local fileVar="${var}_FILE" - local def="${2:-}" - if [ "${!var:-}" ] && [ "${!fileVar:-}" ]; then - echo "Both $var and $fileVar are set (but are exclusive)" - exit 1 - fi - local val="$def" - if [ "${!var:-}" ]; then - val="${!var}" - elif [ "${!fileVar:-}" ]; then - val="$(< "${!fileVar}")" - fi - export "$var"="$val" - unset "$fileVar" -} - -# Loads various settings that are used elsewhere in the script -docker_setup_env() { - # Initialize values that might be stored in a file - - file_env 'MYSQL_AUTOCONF' $MYSQL_DEFAULT_AUTOCONF - file_env 'MYSQL_HOST' $MYSQL_DEFAULT_HOST - file_env 'MYSQL_DNSSEC' 'no' - file_env 'MYSQL_DB' $MYSQL_DEFAULT_DB - file_env 'MYSQL_PASS' $MYSQL_DEFAULT_PASS - file_env 'MYSQL_USER' $MYSQL_DEFAULT_USER - file_env 'MYSQL_PORT' $MYSQL_DEFAULT_PORT -} - -docker_setup_env +[[ -z "$TRACE" ]] || set -x # --help, --version [ "$1" = "--help" ] || [ "$1" = "--version" ] && exec pdns_server $1 + # treat everything except -- as exec cmd [ "${1:0:2}" != "--" ] && exec "$@" -if $MYSQL_AUTOCONF ; then - # Set MySQL Credentials in pdns.conf - sed -r -i "s/^[# ]*gmysql-host=.*/gmysql-host=${MYSQL_HOST}/g" /etc/pdns/pdns.conf - sed -r -i "s/^[# ]*gmysql-port=.*/gmysql-port=${MYSQL_PORT}/g" /etc/pdns/pdns.conf - sed -r -i "s/^[# ]*gmysql-user=.*/gmysql-user=${MYSQL_USER}/g" /etc/pdns/pdns.conf - sed -r -i "s/^[# ]*gmysql-password=.*/gmysql-password=${MYSQL_PASS}/g" /etc/pdns/pdns.conf - sed -r -i "s/^[# ]*gmysql-dbname=.*/gmysql-dbname=${MYSQL_DB}/g" /etc/pdns/pdns.conf - sed -r -i "s/^[# ]*gmysql-dnssec=.*/gmysql-dnssec=${MYSQL_DNSSEC}/g" /etc/pdns/pdns.conf - - MYSQLCMD="mysql --host=${MYSQL_HOST} --user=${MYSQL_USER} --password=${MYSQL_PASS} --port=${MYSQL_PORT} -r -N" - - # wait for Database come ready - isDBup () { - echo "SHOW STATUS" | $MYSQLCMD 1>/dev/null - echo $? - } +# Set credentials to be imported into pdns.conf +case "$AUTOCONF" in + mysql) + export PDNS_LOAD_MODULES=$PDNS_LOAD_MODULES,libgmysqlbackend.so + export PDNS_LAUNCH=gmysql + export PDNS_GMYSQL_HOST=${PDNS_GMYSQL_HOST:-$MYSQL_HOST} + export PDNS_GMYSQL_PORT=${PDNS_GMYSQL_PORT:-$MYSQL_PORT} + export PDNS_GMYSQL_USER=${PDNS_GMYSQL_USER:-$MYSQL_USER} + export PDNS_GMYSQL_PASSWORD=${PDNS_GMYSQL_PASSWORD:-$MYSQL_PASS} + export PDNS_GMYSQL_DBNAME=${PDNS_GMYSQL_DBNAME:-$MYSQL_DB} + export PDNS_GMYSQL_DNSSEC=${PDNS_GMYSQL_DNSSEC:-$MYSQL_DNSSEC} + ;; + postgres) + export PDNS_LOAD_MODULES=$PDNS_LOAD_MODULES,libgpgsqlbackend.so + export PDNS_LAUNCH=gpgsql + export PDNS_GPGSQL_HOST=${PDNS_GPGSQL_HOST:-$PGSQL_HOST} + export PDNS_GPGSQL_PORT=${PDNS_GPGSQL_PORT:-$PGSQL_PORT} + export PDNS_GPGSQL_USER=${PDNS_GPGSQL_USER:-$PGSQL_USER} + export PDNS_GPGSQL_PASSWORD=${PDNS_GPGSQL_PASSWORD:-$PGSQL_PASS} + export PDNS_GPGSQL_DBNAME=${PDNS_GPGSQL_DBNAME:-$PGSQL_DB} + export PDNS_GPGSQL_DNSSEC=${PDNS_GPGSQL_DNSSEC:-$PGSQL_DNSSEC} + export PGPASSWORD=$PDNS_GPGSQL_PASSWORD + ;; + sqlite) + export PDNS_LOAD_MODULES=$PDNS_LOAD_MODULES,libgsqlite3backend.so + export PDNS_LAUNCH=gsqlite3 + export PDNS_GSQLITE3_DATABASE=${PDNS_GSQLITE3_DATABASE:-$SQLITE_DB} + export PDNS_GSQLITE3_PRAGMA_SYNCHRONOUS=${PDNS_GSQLITE3_PRAGMA_SYNCHRONOUS:-$SQLITE_PRAGMA_SYNCHRONOUS} + export PDNS_GSQLITE3_PRAGMA_FOREIGN_KEYS=${PDNS_GSQLITE3_PRAGMA_FOREIGN_KEYS:-$SQLITE_PRAGMA_FOREIGN_KEYS} + export PDNS_GSQLITE3_DNSSEC=${PDNS_GSQLITE3_DNSSEC:-$SQLITE_DNSSEC} + ;; +esac + +MYSQLCMD="mysql -h $MYSQL_HOST -u $MYSQL_USER -p$MYSQL_PASS -r -N" +PGSQLCMD="psql --host=$PGSQL_HOST --username=$PGSQL_USER" + +# wait for Database come ready +isDBup () { + case "$PDNS_LAUNCH" in + gmysql) + echo "SHOW STATUS" | $MYSQLCMD 1>/dev/null + echo $? + ;; + gpgsql) + echo "SELECT 1" | $PGSQLCMD 1>/dev/null + echo $? + ;; + gsqlite3) + echo 0 + ;; + esac +} - RETRY=10 - until [ `isDBup` -eq 0 ] || [ $RETRY -le 0 ] ; do - echo "Waiting for database to come up" - sleep 5 - RETRY=$(expr $RETRY - 1) - done - if [ $RETRY -le 0 ]; then +RETRY=10 +until [ `isDBup` -eq 0 ] || [ $RETRY -le 0 ] ; do + echo "Waiting for database to come up" + sleep 5 + RETRY=$(expr $RETRY - 1) +done +if [ $RETRY -le 0 ]; then + if [[ "$MYSQL_HOST" ]]; then >&2 echo Error: Could not connect to Database on $MYSQL_HOST:$MYSQL_PORT exit 1 + elif [[ "$PGSQL_HOST" ]]; then + >&2 echo Error: Could not connect to Database on $PGSQL_HOST:$PGSQL_PORT + exit 1 fi - - # init database if necessary - echo "CREATE DATABASE IF NOT EXISTS $MYSQL_DB;" | $MYSQLCMD - MYSQLCMD="$MYSQLCMD $MYSQL_DB" - - if [ "$(echo "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = \"$MYSQL_DB\";" | $MYSQLCMD)" -le 1 ]; then - echo Initializing Database - cat /etc/pdns/schema.sql | $MYSQLCMD - - # Run custom mysql post-init sql scripts - if [ -d "/etc/pdns/mysql-postinit" ]; then - for SQLFILE in $(ls -1 /etc/pdns/mysql-postinit/*.sql | sort) ; do - echo Source $SQLFILE - cat $SQLFILE | $MYSQLCMD - done - fi - fi - - unset -v MYSQL_PASS fi -# Run pdns server +# init database and migrate database if necessary +case "$PDNS_LAUNCH" in + gmysql) + echo "CREATE DATABASE IF NOT EXISTS $MYSQL_DB;" | $MYSQLCMD + MYSQLCMD="$MYSQLCMD $MYSQL_DB" + if [ "$(echo "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = \"$MYSQL_DB\";" | $MYSQLCMD)" -le 1 ]; then + echo Initializing Database + cat /etc/pdns/mysql.schema.sql | $MYSQLCMD + # Run custom mysql post-init sql scripts + if [ -d "/etc/pdns/mysql-postinit" ]; then + for SQLFILE in $(ls -1 /etc/pdns/mysql-postinit/*.sql | sort) ; do + echo Source $SQLFILE + cat $SQLFILE | $MYSQLCMD + done + fi + fi + ;; + gpgsql) + if [[ -z "$(echo "SELECT 1 FROM pg_database WHERE datname = '$PGSQL_DB'" | $PGSQLCMD -t)" ]]; then + echo "CREATE DATABASE $PGSQL_DB;" | $PGSQLCMD + fi + PGSQLCMD="$PGSQLCMD $PGSQL_DB" + if [[ -z "$(printf '\dt' | $PGSQLCMD -qAt)" ]]; then + echo Initializing Database + cat /etc/pdns/pgsql.schema.sql | $PGSQLCMD + fi + ;; + gsqlite3) + if [[ ! -f "$PDNS_GSQLITE3_DATABASE" ]]; then + install -D -d -o pdns -g pdns -m 0755 $(dirname $PDNS_GSQLITE3_DATABASE) + cat /etc/pdns/sqlite3.schema.sql | sqlite3 $PDNS_GSQLITE3_DATABASE + chown pdns:pdns $PDNS_GSQLITE3_DATABASE + fi + ;; +esac + +# convert all environment variables prefixed with PDNS_ into pdns config directives +PDNS_LOAD_MODULES="$(echo $PDNS_LOAD_MODULES | sed 's/^,//')" +printenv | grep ^PDNS_ | cut -f2- -d_ | while read var; do + val="${var#*=}" + var="${var%%=*}" + var="$(echo $var | sed -e 's/_/-/g' | tr '[:upper:]' '[:lower:]')" + [[ -z "$TRACE" ]] || echo "$var=$val" + sed -r -i "s#^[# ]*$var=.*#$var=$val#g" /etc/pdns/pdns.conf +done + +# environment hygiene +for var in $(printenv | cut -f1 -d= | grep -v -e HOME -e USER -e PATH ); do unset $var; done +export TZ=UTC LANG=C LC_ALL=C + +# prepare graceful shutdown trap "pdns_control quit" SIGHUP SIGINT SIGTERM +# run the server pdns_server "$@" & wait diff --git a/pdns.conf b/pdns.conf index c0d3841..af49e26 100644 --- a/pdns.conf +++ b/pdns.conf @@ -1,190 +1,595 @@ -# allow-axfr-ips Allow zonetransfers only to these subnets -# allow-axfr-ips=0.0.0.0/0 +# Autogenerated configuration file template +################################# +# 8bit-dns Allow 8bit dns queries +# +# 8bit-dns=no +################################# +# allow-axfr-ips Allow zonetransfers only to these subnets +# +# allow-axfr-ips=127.0.0.0/8,::1 + +################################# +# allow-dnsupdate-from A global setting to allow DNS updates from these IP ranges. +# +# allow-dnsupdate-from=127.0.0.0/8,::1 + +################################# +# allow-notify-from Allow AXFR NOTIFY from these IP ranges. If empty, drop all incoming notifies. +# +# allow-notify-from=0.0.0.0/0,::/0 + +################################# +# allow-recursion List of subnets that are allowed to recurse +# +# allow-recursion=0.0.0.0/0 + +################################# +# allow-unsigned-notify Allow unsigned notifications for TSIG secured domains +# +# allow-unsigned-notify=yes + +################################# +# allow-unsigned-supermaster Allow supermasters to create zones without TSIG signed NOTIFY +# +# allow-unsigned-supermaster=yes + +################################# +# also-notify When notifying a domain, also notify these nameservers +# +# also-notify= + +################################# +# any-to-tcp Answer ANY queries with tc=1, shunting to TCP +# +# any-to-tcp=yes + +################################# +# api Enable/disable the REST API +# +# api=no + +################################# +# api-key Static pre-shared authentication key for access to the REST API +# +# api-key= + +################################# +# api-logfile Location of the server logfile (used by the REST API) +# +# api-logfile=/var/log/pdns.log + +################################# +# api-readonly Disallow data modification through the REST API when set +# +# api-readonly=no + +################################# # cache-ttl Seconds to store packets in the PacketCache -cache-ttl=60 +# +# cache-ttl=20 + +################################# +# carbon-interval Number of seconds between carbon (graphite) updates +# +# carbon-interval=30 + +################################# +# carbon-ourname If set, overrides our reported hostname for carbon stats +# +# carbon-ourname= +################################# +# carbon-server If set, send metrics in carbon (graphite) format to this server +# +# carbon-server= + +################################# # chroot If set, chroot to this directory for more security -# chroot=/var/empty +# +# chroot= +################################# # config-dir Location of configuration directory (pdns.conf) -config-dir=/etc/pdns - -include-dir=/etc/pdns/conf.d +# +# config-dir=/etc/pdns +################################# # config-name Name of this virtual configuration - will rename the binary image +# # config-name= +################################# # control-console Debugging switch - don't use +# # control-console=no +################################# # daemon Operate as a daemon +# daemon=no +################################# +# default-ksk-algorithms Default KSK algorithms +# +# default-ksk-algorithms=ecdsa256 + +################################# +# default-ksk-size Default KSK size (0 means default) +# +# default-ksk-size=0 + +################################# +# default-soa-edit Default SOA-EDIT value +# +# default-soa-edit= + +################################# +# default-soa-edit-signed Default SOA-EDIT value for signed zones +# +# default-soa-edit-signed= + +################################# +# default-soa-mail mail address to insert in the SOA record if none set in the backend +# +# default-soa-mail= + +################################# # default-soa-name name to insert in the SOA record if none set in the backend +# # default-soa-name=a.misconfigured.powerdns.server +################################# # default-ttl Seconds a result is valid if not set otherwise +# # default-ttl=3600 +################################# +# default-zsk-algorithms Default ZSK algorithms +# +# default-zsk-algorithms= + +################################# +# default-zsk-size Default ZSK size (0 means default) +# +# default-zsk-size=0 + +################################# +# direct-dnskey Fetch DNSKEY RRs from backend during DNSKEY synthesis +# +# direct-dnskey=no + +################################# # disable-axfr Disable zonetransfers but do allow TCP queries -disable-axfr=no +# +# disable-axfr=no +################################# +# disable-axfr-rectify Disable the rectify step during an outgoing AXFR. Only required for regression testing. +# +# disable-axfr-rectify=no + +################################# +# disable-syslog Disable logging to syslog, useful when running inside a supervisor that logs stdout +# +disable-syslog=yes + +################################# # disable-tcp Do not listen to TCP queries +# # disable-tcp=no +################################# # distributor-threads Default number of Distributor (backend) threads to start -distributor-threads=1 +# +# distributor-threads=3 -# do-ipv6-additional-processing Do AAAA additional processing -# do-ipv6-additional-processing=no +################################# +# dname-processing If we should support DNAME records +# +# dname-processing=no + +################################# +# dnssec-key-cache-ttl Seconds to cache DNSSEC keys from the database +# +# dnssec-key-cache-ttl=30 -# fancy-records Process URL and MBOXFW records -# fancy-records=no +################################# +# dnsupdate Enable/Disable DNS update (RFC2136) support. Default is no. +# +# dnsupdate=no +################################# +# do-ipv6-additional-processing Do AAAA additional processing +# +# do-ipv6-additional-processing=yes + +################################# +# domain-metadata-cache-ttl Seconds to cache domain metadata from the database +# +# domain-metadata-cache-ttl=60 + +################################# +# edns-subnet-processing If we should act on EDNS Subnet options +# +# edns-subnet-processing=no + +################################# +# entropy-source If set, read entropy from this file +# +# entropy-source=/dev/urandom + +################################# +# experimental-lua-policy-script Lua script for the policy engine +# +# experimental-lua-policy-script= + +################################# +# forward-dnsupdate A global setting to allow DNS update packages that are for a Slave domain, to be forwarded to the master. +# +# forward-dnsupdate=yes + +################################# # guardian Run within a guardian process + guardian=yes +################################# +# include-dir Include *.conf files from this directory +# +# include-dir= + +################################# # launch Which backends to launch and order to query them in +# launch=gmysql -#gmysql-host=mysql -#gmysql-port=3306 -#gmysql-dbname=pdns -#gmysql-user=root -#gmysql-password=root -#gmysql-dnssec=no +################################# # load-modules Load this module - supply absolute or relative path +# # load-modules= +################################# # local-address Local IP addresses to which we bind -local-address=0.0.0.0 +# +# local-address=0.0.0.0 +################################# +# local-address-nonexist-fail Fail to start if one or more of the local-address's do not exist on this server +# +# local-address-nonexist-fail=yes + +################################# # local-ipv6 Local IP address to which we bind -# local-ipv6= +# +# local-ipv6=:: + +################################# +# local-ipv6-nonexist-fail Fail to start if one or more of the local-ipv6 addresses do not exist on this server +# +# local-ipv6-nonexist-fail=yes +################################# # local-port The port on which we listen -local-port=53 +# +# local-port=53 +################################# # log-dns-details If PDNS should log DNS non-erroneous details -# log-dns-details= +# +# log-dns-details=no -# log-failed-updates If PDNS should log failed update requests -# log-failed-updates= - -# logfile Logfile to use (Windows only) -# logfile=pdns.log +################################# +# log-dns-queries If PDNS should log all incoming DNS queries +# +# log-dns-queries=no +################################# # logging-facility Log under a specific facility +# # logging-facility= +################################# # loglevel Amount of logging. Higher is more. Do not set below 3 -loglevel=3 +# +# loglevel=4 +################################# +# lua-prequery-script Lua script with prequery handler (DO NOT USE) +# +# lua-prequery-script= +################################# # master Act as a master -master=yes +# +# master=no + +################################# +# max-cache-entries Maximum number of cache entries +# +# max-cache-entries=1000000 +################################# +# max-ent-entries Maximum number of empty non-terminals in a zone +# +# max-ent-entries=100000 + +################################# +# max-nsec3-iterations Limit the number of NSEC3 hash iterations +# +# max-nsec3-iterations=500 + +################################# # max-queue-length Maximum queuelength before considering situation lost +# # max-queue-length=5000 +################################# +# max-signature-cache-entries Maximum number of signatures cache entries +# +# max-signature-cache-entries= + +################################# # max-tcp-connections Maximum number of TCP connections -# max-tcp-connections=10 +# +# max-tcp-connections=20 +################################# # module-dir Default directory for modules +# # module-dir=/usr/lib/pdns -# negquery-cache-ttl Seconds to store packets in the PacketCache -negquery-cache-ttl=60 +################################# +# negquery-cache-ttl Seconds to store negative query results in the QueryCache +# +# negquery-cache-ttl=60 +################################# # no-shuffle Set this to prevent random shuffling of answers - for regression testing +# # no-shuffle=off +################################# +# non-local-bind Enable binding to non-local addresses by using FREEBIND / BINDANY socket options +# +# non-local-bind=no + +################################# +# only-notify Only send AXFR NOTIFY to these IP addresses or netmasks +# +# only-notify=0.0.0.0/0,::/0 + +################################# # out-of-zone-additional-processing Do out of zone additional processing +# # out-of-zone-additional-processing=yes -# pipebackend-abi-version Version of the pipe backend ABI -# pipebackend-abi-version=1 +################################# +# outgoing-axfr-expand-alias Expand ALIAS records during outgoing AXFR +# +# outgoing-axfr-expand-alias=no + +################################# +# overload-queue-length Maximum queuelength moving to packetcache only +# +# overload-queue-length=0 + +################################# +# prevent-self-notification Don't send notifications to what we think is ourself +# +# prevent-self-notification=yes -# query-cache-ttl Seconds to store packets in the PacketCache +################################# +# query-cache-ttl Seconds to store query results in the QueryCache +# # query-cache-ttl=20 +################################# # query-local-address Source IP address for sending queries -# query-local-address= +# +# query-local-address=0.0.0.0 +################################# +# query-local-address6 Source IPv6 address for sending queries +# +# query-local-address6=:: + +################################# # query-logging Hint backends that queries should be logged +# # query-logging=no +################################# # queue-limit Maximum number of milliseconds to queue a query +# # queue-limit=1500 - -# send-root-referral Send out old-fashioned root-referral instead of ServFail in case of no authority -# send-root-referral=no - +################################# +# receiver-threads Default number of receiver threads to start +# +# receiver-threads=1 + +################################# +# recursive-cache-ttl Seconds to store packets for recursive queries in the PacketCache +# +# recursive-cache-ttl=10 + +################################# +# recursor If recursion is desired, IP address of a recursing nameserver +# +# recursor=no + +################################# +# retrieval-threads Number of AXFR-retrieval threads for slave operation +# +# retrieval-threads=2 + +################################# +# reuseport Enable higher performance on compliant kernels by using SO_REUSEPORT allowing each receiver thread to open its own socket +# +# reuseport=no + +################################# +# security-poll-suffix Domain name from which to query security update notifications +# +# security-poll-suffix=secpoll.powerdns.com. + +################################# +# server-id Returned when queried for 'server.id' TXT or NSID, defaults to hostname - disabled or custom +# +# server-id= + +################################# # setgid If set, change group id to this gid for more security -setgid=pdns +# +# setgid= +################################# # setuid If set, change user id to this uid for more security -setuid=pdns +# +# setuid= -# skip-cname Do not perform CNAME indirection for each query -# skip-cname=no +################################# +# signing-threads Default number of signer threads to start +# +# signing-threads=3 +################################# # slave Act as a slave +# # slave=no -# slave-cycle-interval Reschedule failed SOA serial checks once every .. seconds +################################# +# slave-cycle-interval Schedule slave freshness checks once every .. seconds +# # slave-cycle-interval=60 -# smtpredirector Our smtpredir MX host -# smtpredirector=a.misconfigured.powerdns.smtp.server +################################# +# slave-renotify If we should send out notifications for slaved updates +# +# slave-renotify=no +################################# # soa-expire-default Default SOA expire +# # soa-expire-default=604800 -# soa-minimum-ttl Default SOA mininum ttl +################################# +# soa-minimum-ttl Default SOA minimum ttl +# # soa-minimum-ttl=3600 +################################# # soa-refresh-default Default SOA refresh +# # soa-refresh-default=10800 +################################# # soa-retry-default Default SOA retry +# # soa-retry-default=3600 -# soa-serial-offset Make sure that no SOA serial is less than this number -# soa-serial-offset=0 - -# socket-dir Where the controlsocket will live -socket-dir=/var/run - -# strict-rfc-axfrs Perform strictly rfc compliant axfrs (very slow) -# strict-rfc-axfrs=no - +################################# +# socket-dir Where the controlsocket will live, /var/run when unset and not chrooted +# +# socket-dir= + +################################# +# tcp-control-address If set, PowerDNS can be controlled over TCP on this address +# +# tcp-control-address= + +################################# +# tcp-control-port If set, PowerDNS can be controlled over TCP on this address +# +# tcp-control-port=53000 + +################################# +# tcp-control-range If set, remote control of PowerDNS is possible over these networks only +# +# tcp-control-range=127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10 + +################################# +# tcp-control-secret If set, PowerDNS can be controlled over TCP after passing this secret +# +# tcp-control-secret= + +################################# +# traceback-handler Enable the traceback handler (Linux only) +# +# traceback-handler=yes + +################################# # trusted-notification-proxy IP address of incoming notification proxy +# # trusted-notification-proxy= -# urlredirector Where we send hosts to that need to be url redirected -# urlredirector=127.0.0.1 +################################# +# udp-truncation-threshold Maximum UDP response size before we truncate +# +# udp-truncation-threshold=1680 +################################# # version-string PowerDNS version in packets - full, anonymous, powerdns or custom -version-string=powerdns +# +# version-string=full +################################# # webserver Start a webserver for monitoring -webserver=no +# +# webserver=no +################################# # webserver-address IP Address of webserver to listen on +# # webserver-address=127.0.0.1 +################################# +# webserver-allow-from Webserver access is only allowed from these subnets +# +# webserver-allow-from=0.0.0.0/0,::/0 + +################################# # webserver-password Password required for accessing the webserver +# # webserver-password= +################################# # webserver-port Port of webserver to listen on +# # webserver-port=8081 +################################# # webserver-print-arguments If the webserver should print arguments +# # webserver-print-arguments=no -# wildcard-url Process URL and MBOXFW records -# wildcard-url=no +################################# +# write-pid Write a PID file +# +# write-pid=yes + +################################# +# xfr-max-received-mbytes Maximum number of megabytes received from an incoming XFR +# +# xfr-max-received-mbytes=100 + +# launch Which backends to launch and order to query them in +#gmysql-host=mysql +#gmysql-port=3306 +#gmysql-dbname=pdns +#gmysql-user=root +#gmysql-password=root +#gmysql-dnssec=no +#gpgsql-host=postgres +#gpgsql-port=5432 +#gpgsql-dbname=pdns +#gpgsql-user=postgres +#gpgsql-password=postgres +#gpgsql-dnssec=no + +#gsqlite3-database=/pdns.sqlite3 +#gsqlite3-pragma-synchronous=1 +#gsqlite3-pragma-foreign-keys=1 +#gsqlite3-dnssec=no diff --git a/schema.sql b/sql/mysql.schema.sql similarity index 100% rename from schema.sql rename to sql/mysql.schema.sql diff --git a/sql/pgsql.schema.sql b/sql/pgsql.schema.sql new file mode 100644 index 0000000..a853deb --- /dev/null +++ b/sql/pgsql.schema.sql @@ -0,0 +1,95 @@ +CREATE TABLE domains ( + id SERIAL PRIMARY KEY, + name VARCHAR(255) NOT NULL, + master VARCHAR(128) DEFAULT NULL, + last_check INT DEFAULT NULL, + type VARCHAR(6) NOT NULL, + notified_serial INT DEFAULT NULL, + account VARCHAR(40) DEFAULT NULL, + CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) +); + +CREATE UNIQUE INDEX name_index ON domains(name); + + +CREATE TABLE records ( + id SERIAL PRIMARY KEY, + domain_id INT DEFAULT NULL, + name VARCHAR(255) DEFAULT NULL, + type VARCHAR(10) DEFAULT NULL, + content VARCHAR(65535) DEFAULT NULL, + ttl INT DEFAULT NULL, + prio INT DEFAULT NULL, + change_date INT DEFAULT NULL, + disabled BOOL DEFAULT 'f', + ordername VARCHAR(255), + auth BOOL DEFAULT 't', + CONSTRAINT domain_exists + FOREIGN KEY(domain_id) REFERENCES domains(id) + ON DELETE CASCADE, + CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) +); + +CREATE INDEX rec_name_index ON records(name); +CREATE INDEX nametype_index ON records(name,type); +CREATE INDEX domain_id ON records(domain_id); +CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops); + + +CREATE TABLE supermasters ( + ip INET NOT NULL, + nameserver VARCHAR(255) NOT NULL, + account VARCHAR(40) NOT NULL, + PRIMARY KEY(ip, nameserver) +); + + +CREATE TABLE comments ( + id SERIAL PRIMARY KEY, + domain_id INT NOT NULL, + name VARCHAR(255) NOT NULL, + type VARCHAR(10) NOT NULL, + modified_at INT NOT NULL, + account VARCHAR(40) DEFAULT NULL, + comment VARCHAR(65535) NOT NULL, + CONSTRAINT domain_exists + FOREIGN KEY(domain_id) REFERENCES domains(id) + ON DELETE CASCADE, + CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) +); + +CREATE INDEX comments_domain_id_idx ON comments (domain_id); +CREATE INDEX comments_name_type_idx ON comments (name, type); +CREATE INDEX comments_order_idx ON comments (domain_id, modified_at); + + +CREATE TABLE domainmetadata ( + id SERIAL PRIMARY KEY, + domain_id INT REFERENCES domains(id) ON DELETE CASCADE, + kind VARCHAR(32), + content TEXT +); + +CREATE INDEX domainidmetaindex ON domainmetadata(domain_id); + + +CREATE TABLE cryptokeys ( + id SERIAL PRIMARY KEY, + domain_id INT REFERENCES domains(id) ON DELETE CASCADE, + flags INT NOT NULL, + active BOOL, + content TEXT +); + +CREATE INDEX domainidindex ON cryptokeys(domain_id); + + +CREATE TABLE tsigkeys ( + id SERIAL PRIMARY KEY, + name VARCHAR(255), + algorithm VARCHAR(50), + secret VARCHAR(255), + CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) +); + +CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm); \ No newline at end of file diff --git a/sql/sqlite3.schema.sql b/sql/sqlite3.schema.sql new file mode 100644 index 0000000..c9e12a1 --- /dev/null +++ b/sql/sqlite3.schema.sql @@ -0,0 +1,92 @@ +PRAGMA foreign_keys = 1; + +CREATE TABLE domains ( + id INTEGER PRIMARY KEY, + name VARCHAR(255) NOT NULL COLLATE NOCASE, + master VARCHAR(128) DEFAULT NULL, + last_check INTEGER DEFAULT NULL, + type VARCHAR(6) NOT NULL, + notified_serial INTEGER DEFAULT NULL, + account VARCHAR(40) DEFAULT NULL +); + +CREATE UNIQUE INDEX name_index ON domains(name); + + +CREATE TABLE records ( + id INTEGER PRIMARY KEY, + domain_id INTEGER DEFAULT NULL, + name VARCHAR(255) DEFAULT NULL, + type VARCHAR(10) DEFAULT NULL, + content VARCHAR(65535) DEFAULT NULL, + ttl INTEGER DEFAULT NULL, + prio INTEGER DEFAULT NULL, + change_date INTEGER DEFAULT NULL, + disabled BOOLEAN DEFAULT 0, + ordername VARCHAR(255), + auth BOOL DEFAULT 1, + FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX rec_name_index ON records(name); +CREATE INDEX nametype_index ON records(name,type); +CREATE INDEX domain_id ON records(domain_id); +CREATE INDEX orderindex ON records(ordername); + + +CREATE TABLE supermasters ( + ip VARCHAR(64) NOT NULL, + nameserver VARCHAR(255) NOT NULL COLLATE NOCASE, + account VARCHAR(40) NOT NULL +); + +CREATE UNIQUE INDEX ip_nameserver_pk ON supermasters(ip, nameserver); + + +CREATE TABLE comments ( + id INTEGER PRIMARY KEY, + domain_id INTEGER NOT NULL, + name VARCHAR(255) NOT NULL, + type VARCHAR(10) NOT NULL, + modified_at INT NOT NULL, + account VARCHAR(40) DEFAULT NULL, + comment VARCHAR(65535) NOT NULL, + FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX comments_domain_id_index ON comments (domain_id); +CREATE INDEX comments_nametype_index ON comments (name, type); +CREATE INDEX comments_order_idx ON comments (domain_id, modified_at); + + +CREATE TABLE domainmetadata ( + id INTEGER PRIMARY KEY, + domain_id INT NOT NULL, + kind VARCHAR(32) COLLATE NOCASE, + content TEXT, + FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX domainmetaidindex ON domainmetadata(domain_id); + + +CREATE TABLE cryptokeys ( + id INTEGER PRIMARY KEY, + domain_id INT NOT NULL, + flags INT NOT NULL, + active BOOL, + content TEXT, + FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX domainidindex ON cryptokeys(domain_id); + + +CREATE TABLE tsigkeys ( + id INTEGER PRIMARY KEY, + name VARCHAR(255) COLLATE NOCASE, + algorithm VARCHAR(50) COLLATE NOCASE, + secret VARCHAR(255) +); + +CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm); \ No newline at end of file From 93b85f6596d1c02996d4b8de65dec80190947249 Mon Sep 17 00:00:00 2001 From: Manuel Mazzuola Date: Thu, 31 Jan 2019 11:22:50 +0100 Subject: [PATCH 02/11] Add backward compatibility --- entrypoint.sh | 5 ++++- pdns.conf | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index f84b535..a8df8fa 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -9,6 +9,9 @@ set -e # treat everything except -- as exec cmd [ "${1:0:2}" != "--" ] && exec "$@" +# Add backward compatibility +[[ "$MYSQL_AUTOCONF" == false ]] && AUTOCONF=false + # Set credentials to be imported into pdns.conf case "$AUTOCONF" in mysql) @@ -56,7 +59,7 @@ isDBup () { echo "SELECT 1" | $PGSQLCMD 1>/dev/null echo $? ;; - gsqlite3) + *) echo 0 ;; esac diff --git a/pdns.conf b/pdns.conf index af49e26..5ead7e4 100644 --- a/pdns.conf +++ b/pdns.conf @@ -242,7 +242,7 @@ guardian=yes ################################# # launch Which backends to launch and order to query them in # -launch=gmysql +launch=bind ################################# # load-modules Load this module - supply absolute or relative path From a7b4c0fc75271037ab419ddbec673f9546ab88a2 Mon Sep 17 00:00:00 2001 From: Manuel Mazzuola Date: Tue, 30 Apr 2019 15:02:28 +0200 Subject: [PATCH 03/11] Add TRACE documentation --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a49fddd..ae0d991 100644 --- a/README.md +++ b/README.md @@ -99,6 +99,7 @@ $ docker run --name pdns \ * Want to disable database initialization? Use `AUTOCONF=false` * Want to apply 12Factor-Pattern? Apply environment variables of the form `PDNS_$pdns-config-variable=$config-value`, like `PDNS_WEBSERVER=yes` * Want to use own config files? Mount a Volume to `/etc/pdns/conf.d` or simply overwrite `/etc/pdns/pdns.conf` +* Use `TRACE=true` to debug the pdns config directives **PowerDNS Configuration:** From 3d2aba0e876691a231f33e6da89e828af6ae7fad Mon Sep 17 00:00:00 2001 From: Manuel Mazzuola Date: Mon, 10 Feb 2020 16:47:11 +0100 Subject: [PATCH 04/11] Update contributors --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 4464962..91022d7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM alpine:3.9 LABEL \ MAINTAINER="Christoph Wiechert " \ - CONTRIBUTORS="Mathias Kaufmann " + CONTRIBUTORS="Mathias Kaufmann , Cloudesire " ENV REFRESHED_AT="2019-10-10" \ POWERDNS_VERSION=4.3.1 \ From 2be08b8da3f1368097d02bd41b5db472b60e1c4b Mon Sep 17 00:00:00 2001 From: Antoine Millet Date: Fri, 6 Nov 2020 18:29:20 +0100 Subject: [PATCH 05/11] Rewrite Dockerfile to use multi-stage Also: - Removed libboost_program_options hack (shipped with boost-program_options package) - Now use sql files from release tarball --- Dockerfile | 52 ++++++++++++----------- entrypoint.sh | 6 +-- sql/mysql.schema.sql | 89 --------------------------------------- sql/pgsql.schema.sql | 95 ------------------------------------------ sql/sqlite3.schema.sql | 92 ---------------------------------------- 5 files changed, 31 insertions(+), 303 deletions(-) delete mode 100644 sql/mysql.schema.sql delete mode 100644 sql/pgsql.schema.sql delete mode 100644 sql/sqlite3.schema.sql diff --git a/Dockerfile b/Dockerfile index 91022d7..8b32cc1 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,35 @@ -FROM alpine:3.9 +FROM alpine:3.9 as base + +ENV REFRESHED_AT="2019-10-10" \ + POWERDNS_VERSION="4.3.1" \ + BUILD_DEPS="g++ make mariadb-dev postgresql-dev sqlite-dev curl boost-dev mariadb-connector-c-dev" \ + RUN_DEPS="bash libpq sqlite-libs libstdc++ libgcc mariadb-client postgresql-client sqlite mariadb-connector-c lua-dev curl-dev boost-program_options" \ + POWERDNS_MODULES="bind gmysql gpgsql gsqlite3" + +FROM base AS build + +RUN apk --update add $BUILD_DEPS $RUN_DEPS +RUN curl -sSL https://downloads.powerdns.com/releases/pdns-$POWERDNS_VERSION.tar.bz2 | tar xj -C /tmp/ +WORKDIR /tmp/pdns-$POWERDNS_VERSION +RUN ./configure --prefix="" --exec-prefix=/usr --sysconfdir=/etc/pdns --with-modules="$POWERDNS_MODULES" +RUN make +RUN DESTDIR="/pdnsbuild" make install-strip +RUN mkdir -p /pdnsbuild/etc/pdns/conf.d /pdnsbuild/etc/pdns/sql +RUN cp modules/gmysqlbackend/*.sql modules/gpgsqlbackend/*.sql modules/gsqlite3backend/*.sql /pdnsbuild/etc/pdns/sql/ + +FROM base + +COPY --from=build /pdnsbuild / +RUN apk add $RUN_DEPS && \ + addgroup -S pdns 2>/dev/null && \ + adduser -S -D -H -h /var/empty -s /bin/false -G pdns -g pdns pdns 2>/dev/null && \ + rm /var/cache/apk/* LABEL \ MAINTAINER="Christoph Wiechert " \ CONTRIBUTORS="Mathias Kaufmann , Cloudesire " -ENV REFRESHED_AT="2019-10-10" \ - POWERDNS_VERSION=4.3.1 \ - AUTOCONF=mysql \ +ENV AUTOCONF=mysql \ MYSQL_HOST="mysql" \ MYSQL_PORT="3306" \ MYSQL_USER="root" \ @@ -20,26 +43,7 @@ ENV REFRESHED_AT="2019-10-10" \ PGSQL_DB="pdns" \ SQLITE_DB="pdns.sqlite3" -RUN apk --update add bash libpq sqlite-libs libstdc++ libgcc mariadb-client postgresql-client sqlite mariadb-connector-c lua-dev curl-dev && \ - apk add --virtual build-deps \ - g++ make mariadb-dev postgresql-dev sqlite-dev curl boost-dev mariadb-connector-c-dev && \ - curl -sSL https://downloads.powerdns.com/releases/pdns-$POWERDNS_VERSION.tar.bz2 | tar xj -C /tmp && \ - cd /tmp/pdns-$POWERDNS_VERSION && \ - ./configure --prefix="" --exec-prefix=/usr --sysconfdir=/etc/pdns \ - --with-modules="bind gmysql gpgsql gsqlite3" && \ - make && make install-strip && cd / && \ - mkdir -p /etc/pdns/conf.d && \ - addgroup -S pdns 2>/dev/null && \ - adduser -S -D -H -h /var/empty -s /bin/false -G pdns -g pdns pdns 2>/dev/null && \ - cp /usr/lib/libboost_program_options-mt.so* /tmp && \ - apk del --purge build-deps && \ - mv /tmp/lib* /usr/lib/ && \ - rm -rf /tmp/pdns-$POWERDNS_VERSION /var/cache/apk/* - EXPOSE 53/tcp 53/udp - -ADD sql/* pdns.conf /etc/pdns/ - +ADD pdns.conf /etc/pdns/ ADD entrypoint.sh /bin/powerdns - ENTRYPOINT ["powerdns"] diff --git a/entrypoint.sh b/entrypoint.sh index a8df8fa..9f21927 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -88,7 +88,7 @@ case "$PDNS_LAUNCH" in MYSQLCMD="$MYSQLCMD $MYSQL_DB" if [ "$(echo "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = \"$MYSQL_DB\";" | $MYSQLCMD)" -le 1 ]; then echo Initializing Database - cat /etc/pdns/mysql.schema.sql | $MYSQLCMD + cat /etc/pdns/sql/schema.mysql.sql | $MYSQLCMD # Run custom mysql post-init sql scripts if [ -d "/etc/pdns/mysql-postinit" ]; then for SQLFILE in $(ls -1 /etc/pdns/mysql-postinit/*.sql | sort) ; do @@ -105,13 +105,13 @@ case "$PDNS_LAUNCH" in PGSQLCMD="$PGSQLCMD $PGSQL_DB" if [[ -z "$(printf '\dt' | $PGSQLCMD -qAt)" ]]; then echo Initializing Database - cat /etc/pdns/pgsql.schema.sql | $PGSQLCMD + cat /etc/pdns/sql/schema.pgsql.sql | $PGSQLCMD fi ;; gsqlite3) if [[ ! -f "$PDNS_GSQLITE3_DATABASE" ]]; then install -D -d -o pdns -g pdns -m 0755 $(dirname $PDNS_GSQLITE3_DATABASE) - cat /etc/pdns/sqlite3.schema.sql | sqlite3 $PDNS_GSQLITE3_DATABASE + cat /etc/pdns/sql/schema.sqlite3.sql | sqlite3 $PDNS_GSQLITE3_DATABASE chown pdns:pdns $PDNS_GSQLITE3_DATABASE fi ;; diff --git a/sql/mysql.schema.sql b/sql/mysql.schema.sql deleted file mode 100644 index c923035..0000000 --- a/sql/mysql.schema.sql +++ /dev/null @@ -1,89 +0,0 @@ -CREATE TABLE domains ( - id INT AUTO_INCREMENT, - name VARCHAR(255) NOT NULL, - master VARCHAR(128) DEFAULT NULL, - last_check INT DEFAULT NULL, - type VARCHAR(6) NOT NULL, - notified_serial INT UNSIGNED DEFAULT NULL, - account VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL, - PRIMARY KEY (id) -) Engine=InnoDB CHARACTER SET 'latin1'; - -CREATE UNIQUE INDEX name_index ON domains(name); - - -CREATE TABLE records ( - id BIGINT AUTO_INCREMENT, - domain_id INT DEFAULT NULL, - name VARCHAR(255) DEFAULT NULL, - type VARCHAR(10) DEFAULT NULL, - content VARCHAR(64000) DEFAULT NULL, - ttl INT DEFAULT NULL, - prio INT DEFAULT NULL, - disabled TINYINT(1) DEFAULT 0, - ordername VARCHAR(255) BINARY DEFAULT NULL, - auth TINYINT(1) DEFAULT 1, - PRIMARY KEY (id) -) Engine=InnoDB CHARACTER SET 'latin1'; - -CREATE INDEX nametype_index ON records(name,type); -CREATE INDEX domain_id ON records(domain_id); -CREATE INDEX ordername ON records (ordername); - - -CREATE TABLE supermasters ( - ip VARCHAR(64) NOT NULL, - nameserver VARCHAR(255) NOT NULL, - account VARCHAR(40) CHARACTER SET 'utf8' NOT NULL, - PRIMARY KEY (ip, nameserver) -) Engine=InnoDB CHARACTER SET 'latin1'; - - -CREATE TABLE comments ( - id INT AUTO_INCREMENT, - domain_id INT NOT NULL, - name VARCHAR(255) NOT NULL, - type VARCHAR(10) NOT NULL, - modified_at INT NOT NULL, - account VARCHAR(40) CHARACTER SET 'utf8' DEFAULT NULL, - comment TEXT CHARACTER SET 'utf8' NOT NULL, - PRIMARY KEY (id) -) Engine=InnoDB CHARACTER SET 'latin1'; - -CREATE INDEX comments_name_type_idx ON comments (name, type); -CREATE INDEX comments_order_idx ON comments (domain_id, modified_at); - - -CREATE TABLE domainmetadata ( - id INT AUTO_INCREMENT, - domain_id INT NOT NULL, - kind VARCHAR(32), - content TEXT, - PRIMARY KEY (id) -) Engine=InnoDB CHARACTER SET 'latin1'; - -CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind); - - -CREATE TABLE cryptokeys ( - id INT AUTO_INCREMENT, - domain_id INT NOT NULL, - flags INT NOT NULL, - active BOOL, - published BOOL DEFAULT 1, - content TEXT, - PRIMARY KEY(id) -) Engine=InnoDB CHARACTER SET 'latin1'; - -CREATE INDEX domainidindex ON cryptokeys(domain_id); - - -CREATE TABLE tsigkeys ( - id INT AUTO_INCREMENT, - name VARCHAR(255), - algorithm VARCHAR(50), - secret VARCHAR(255), - PRIMARY KEY (id) -) Engine=InnoDB CHARACTER SET 'latin1'; - -CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm); diff --git a/sql/pgsql.schema.sql b/sql/pgsql.schema.sql deleted file mode 100644 index a853deb..0000000 --- a/sql/pgsql.schema.sql +++ /dev/null @@ -1,95 +0,0 @@ -CREATE TABLE domains ( - id SERIAL PRIMARY KEY, - name VARCHAR(255) NOT NULL, - master VARCHAR(128) DEFAULT NULL, - last_check INT DEFAULT NULL, - type VARCHAR(6) NOT NULL, - notified_serial INT DEFAULT NULL, - account VARCHAR(40) DEFAULT NULL, - CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) -); - -CREATE UNIQUE INDEX name_index ON domains(name); - - -CREATE TABLE records ( - id SERIAL PRIMARY KEY, - domain_id INT DEFAULT NULL, - name VARCHAR(255) DEFAULT NULL, - type VARCHAR(10) DEFAULT NULL, - content VARCHAR(65535) DEFAULT NULL, - ttl INT DEFAULT NULL, - prio INT DEFAULT NULL, - change_date INT DEFAULT NULL, - disabled BOOL DEFAULT 'f', - ordername VARCHAR(255), - auth BOOL DEFAULT 't', - CONSTRAINT domain_exists - FOREIGN KEY(domain_id) REFERENCES domains(id) - ON DELETE CASCADE, - CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) -); - -CREATE INDEX rec_name_index ON records(name); -CREATE INDEX nametype_index ON records(name,type); -CREATE INDEX domain_id ON records(domain_id); -CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops); - - -CREATE TABLE supermasters ( - ip INET NOT NULL, - nameserver VARCHAR(255) NOT NULL, - account VARCHAR(40) NOT NULL, - PRIMARY KEY(ip, nameserver) -); - - -CREATE TABLE comments ( - id SERIAL PRIMARY KEY, - domain_id INT NOT NULL, - name VARCHAR(255) NOT NULL, - type VARCHAR(10) NOT NULL, - modified_at INT NOT NULL, - account VARCHAR(40) DEFAULT NULL, - comment VARCHAR(65535) NOT NULL, - CONSTRAINT domain_exists - FOREIGN KEY(domain_id) REFERENCES domains(id) - ON DELETE CASCADE, - CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) -); - -CREATE INDEX comments_domain_id_idx ON comments (domain_id); -CREATE INDEX comments_name_type_idx ON comments (name, type); -CREATE INDEX comments_order_idx ON comments (domain_id, modified_at); - - -CREATE TABLE domainmetadata ( - id SERIAL PRIMARY KEY, - domain_id INT REFERENCES domains(id) ON DELETE CASCADE, - kind VARCHAR(32), - content TEXT -); - -CREATE INDEX domainidmetaindex ON domainmetadata(domain_id); - - -CREATE TABLE cryptokeys ( - id SERIAL PRIMARY KEY, - domain_id INT REFERENCES domains(id) ON DELETE CASCADE, - flags INT NOT NULL, - active BOOL, - content TEXT -); - -CREATE INDEX domainidindex ON cryptokeys(domain_id); - - -CREATE TABLE tsigkeys ( - id SERIAL PRIMARY KEY, - name VARCHAR(255), - algorithm VARCHAR(50), - secret VARCHAR(255), - CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))) -); - -CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm); \ No newline at end of file diff --git a/sql/sqlite3.schema.sql b/sql/sqlite3.schema.sql deleted file mode 100644 index c9e12a1..0000000 --- a/sql/sqlite3.schema.sql +++ /dev/null @@ -1,92 +0,0 @@ -PRAGMA foreign_keys = 1; - -CREATE TABLE domains ( - id INTEGER PRIMARY KEY, - name VARCHAR(255) NOT NULL COLLATE NOCASE, - master VARCHAR(128) DEFAULT NULL, - last_check INTEGER DEFAULT NULL, - type VARCHAR(6) NOT NULL, - notified_serial INTEGER DEFAULT NULL, - account VARCHAR(40) DEFAULT NULL -); - -CREATE UNIQUE INDEX name_index ON domains(name); - - -CREATE TABLE records ( - id INTEGER PRIMARY KEY, - domain_id INTEGER DEFAULT NULL, - name VARCHAR(255) DEFAULT NULL, - type VARCHAR(10) DEFAULT NULL, - content VARCHAR(65535) DEFAULT NULL, - ttl INTEGER DEFAULT NULL, - prio INTEGER DEFAULT NULL, - change_date INTEGER DEFAULT NULL, - disabled BOOLEAN DEFAULT 0, - ordername VARCHAR(255), - auth BOOL DEFAULT 1, - FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE -); - -CREATE INDEX rec_name_index ON records(name); -CREATE INDEX nametype_index ON records(name,type); -CREATE INDEX domain_id ON records(domain_id); -CREATE INDEX orderindex ON records(ordername); - - -CREATE TABLE supermasters ( - ip VARCHAR(64) NOT NULL, - nameserver VARCHAR(255) NOT NULL COLLATE NOCASE, - account VARCHAR(40) NOT NULL -); - -CREATE UNIQUE INDEX ip_nameserver_pk ON supermasters(ip, nameserver); - - -CREATE TABLE comments ( - id INTEGER PRIMARY KEY, - domain_id INTEGER NOT NULL, - name VARCHAR(255) NOT NULL, - type VARCHAR(10) NOT NULL, - modified_at INT NOT NULL, - account VARCHAR(40) DEFAULT NULL, - comment VARCHAR(65535) NOT NULL, - FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE -); - -CREATE INDEX comments_domain_id_index ON comments (domain_id); -CREATE INDEX comments_nametype_index ON comments (name, type); -CREATE INDEX comments_order_idx ON comments (domain_id, modified_at); - - -CREATE TABLE domainmetadata ( - id INTEGER PRIMARY KEY, - domain_id INT NOT NULL, - kind VARCHAR(32) COLLATE NOCASE, - content TEXT, - FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE -); - -CREATE INDEX domainmetaidindex ON domainmetadata(domain_id); - - -CREATE TABLE cryptokeys ( - id INTEGER PRIMARY KEY, - domain_id INT NOT NULL, - flags INT NOT NULL, - active BOOL, - content TEXT, - FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE -); - -CREATE INDEX domainidindex ON cryptokeys(domain_id); - - -CREATE TABLE tsigkeys ( - id INTEGER PRIMARY KEY, - name VARCHAR(255) COLLATE NOCASE, - algorithm VARCHAR(50) COLLATE NOCASE, - secret VARCHAR(255) -); - -CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm); \ No newline at end of file From 70653822bf83100038eb326d32fe59c86e08f151 Mon Sep 17 00:00:00 2001 From: Antoine Millet Date: Fri, 6 Nov 2020 18:50:18 +0100 Subject: [PATCH 06/11] Removed mysql post-init processing --- entrypoint.sh | 7 ------- 1 file changed, 7 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index 9f21927..7f51800 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -89,13 +89,6 @@ case "$PDNS_LAUNCH" in if [ "$(echo "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = \"$MYSQL_DB\";" | $MYSQLCMD)" -le 1 ]; then echo Initializing Database cat /etc/pdns/sql/schema.mysql.sql | $MYSQLCMD - # Run custom mysql post-init sql scripts - if [ -d "/etc/pdns/mysql-postinit" ]; then - for SQLFILE in $(ls -1 /etc/pdns/mysql-postinit/*.sql | sort) ; do - echo Source $SQLFILE - cat $SQLFILE | $MYSQLCMD - done - fi fi ;; gpgsql) From 33670f082e7d9a3b14e870490cda94372c20c694 Mon Sep 17 00:00:00 2001 From: Antoine Millet Date: Fri, 6 Nov 2020 19:11:49 +0100 Subject: [PATCH 07/11] Replaced per-backend DNSSEC variable by global one --- README.md | 2 +- entrypoint.sh | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ae0d991..427e1a8 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ $ docker run --name pdns \ * `PGSQL_DB=pdns` * SQLite connection settings * `SQLITE_DB=/pdns.sqlite3` -* DNSSEC is disabled by default, to enable use `MYSQL_DNSSEC=yes` +* DNSSEC is disabled by default, to enable use `DNSSEC=yes` * Want to disable database initialization? Use `AUTOCONF=false` * Want to apply 12Factor-Pattern? Apply environment variables of the form `PDNS_$pdns-config-variable=$config-value`, like `PDNS_WEBSERVER=yes` * Want to use own config files? Mount a Volume to `/etc/pdns/conf.d` or simply overwrite `/etc/pdns/pdns.conf` diff --git a/entrypoint.sh b/entrypoint.sh index 7f51800..e3abcba 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -22,7 +22,7 @@ case "$AUTOCONF" in export PDNS_GMYSQL_USER=${PDNS_GMYSQL_USER:-$MYSQL_USER} export PDNS_GMYSQL_PASSWORD=${PDNS_GMYSQL_PASSWORD:-$MYSQL_PASS} export PDNS_GMYSQL_DBNAME=${PDNS_GMYSQL_DBNAME:-$MYSQL_DB} - export PDNS_GMYSQL_DNSSEC=${PDNS_GMYSQL_DNSSEC:-$MYSQL_DNSSEC} + export PDNS_GMYSQL_DNSSEC=${PDNS_GMYSQL_DNSSEC:-$DNSSEC} ;; postgres) export PDNS_LOAD_MODULES=$PDNS_LOAD_MODULES,libgpgsqlbackend.so @@ -32,7 +32,7 @@ case "$AUTOCONF" in export PDNS_GPGSQL_USER=${PDNS_GPGSQL_USER:-$PGSQL_USER} export PDNS_GPGSQL_PASSWORD=${PDNS_GPGSQL_PASSWORD:-$PGSQL_PASS} export PDNS_GPGSQL_DBNAME=${PDNS_GPGSQL_DBNAME:-$PGSQL_DB} - export PDNS_GPGSQL_DNSSEC=${PDNS_GPGSQL_DNSSEC:-$PGSQL_DNSSEC} + export PDNS_GPGSQL_DNSSEC=${PDNS_GPGSQL_DNSSEC:-$DNSSEC} export PGPASSWORD=$PDNS_GPGSQL_PASSWORD ;; sqlite) @@ -41,7 +41,7 @@ case "$AUTOCONF" in export PDNS_GSQLITE3_DATABASE=${PDNS_GSQLITE3_DATABASE:-$SQLITE_DB} export PDNS_GSQLITE3_PRAGMA_SYNCHRONOUS=${PDNS_GSQLITE3_PRAGMA_SYNCHRONOUS:-$SQLITE_PRAGMA_SYNCHRONOUS} export PDNS_GSQLITE3_PRAGMA_FOREIGN_KEYS=${PDNS_GSQLITE3_PRAGMA_FOREIGN_KEYS:-$SQLITE_PRAGMA_FOREIGN_KEYS} - export PDNS_GSQLITE3_DNSSEC=${PDNS_GSQLITE3_DNSSEC:-$SQLITE_DNSSEC} + export PDNS_GSQLITE3_DNSSEC=${PDNS_GSQLITE3_DNSSEC:-$DNSSEC} ;; esac From 1641315c725ccd5415c70a28da3220ef5ba8c53d Mon Sep 17 00:00:00 2001 From: Antoine Millet Date: Sat, 7 Nov 2020 01:24:13 +0100 Subject: [PATCH 08/11] Added a docker-compose file used to test the different available backends --- test/docker-compose.yml | 54 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 test/docker-compose.yml diff --git a/test/docker-compose.yml b/test/docker-compose.yml new file mode 100644 index 0000000..ff49722 --- /dev/null +++ b/test/docker-compose.yml @@ -0,0 +1,54 @@ +version: "3" + +services: + mysql: + image: mariadb:10.5 + environment: + MYSQL_ROOT_PASSWORD: secret + volumes: + - mysql_volume:/var/lib/mysql + + psql: + image: postgres:13 + environment: + POSTGRES_PASSWORD: secret + volumes: + - psql_volume:/var/lib/postgresql + + pdns_mysql: + image: naps/powerdns + environment: + AUTOCONF: mysql + MYSQL_HOST: mysql + MYSQL_USER: root + MYSQL_PASS: secret + command: + - --cache-ttl=120 + - --allow-axfr-ips=127.0.0.1,123.1.2.3 + + pdns_psql: + image: naps/powerdns + environment: + AUTOCONF: psql + PSQL_HOST: psql + PSQL_USER: root + PSQL_PASS: secret + command: + - --cache-ttl=120 + - --allow-axfr-ips=127.0.0.1,123.1.2.3 + + pdns_sqlite: + image: naps/powerdns + environment: + AUTOCONF: sqlite + SQLITE_DB: /data/db.sqlite + command: + - --cache-ttl=120 + - --allow-axfr-ips=127.0.0.1,123.1.2.3 + volumes: + - sqlite_volume:/data + +volumes: + mysql_volume: {} + psql_volume: {} + sqlite_volume: {} \ No newline at end of file From 5e344555a8cfc250e53e94c213e9c19ce554c7bc Mon Sep 17 00:00:00 2001 From: Antoine Millet Date: Fri, 27 Nov 2020 16:34:20 +0100 Subject: [PATCH 09/11] Fixed psql env vars of test docker-compose --- test/docker-compose.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/docker-compose.yml b/test/docker-compose.yml index ff49722..8425726 100644 --- a/test/docker-compose.yml +++ b/test/docker-compose.yml @@ -29,10 +29,10 @@ services: pdns_psql: image: naps/powerdns environment: - AUTOCONF: psql - PSQL_HOST: psql - PSQL_USER: root - PSQL_PASS: secret + AUTOCONF: postgres + PGSQL_HOST: psql + PGSQL_USER: postgres + PGSQL_PASS: secret command: - --cache-ttl=120 - --allow-axfr-ips=127.0.0.1,123.1.2.3 From ce711765b1093ad269e9594b837761ac669bbfac Mon Sep 17 00:00:00 2001 From: Antoine Millet Date: Sat, 28 Nov 2020 13:35:14 +0100 Subject: [PATCH 10/11] Implemented automatic schema migration --- Dockerfile | 7 ++++- README.md | 5 ++++ entrypoint.sh | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8b32cc1..712d9bf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -30,18 +30,23 @@ LABEL \ CONTRIBUTORS="Mathias Kaufmann , Cloudesire " ENV AUTOCONF=mysql \ + AUTO_SCHEMA_MIGRATION="no" \ MYSQL_HOST="mysql" \ MYSQL_PORT="3306" \ MYSQL_USER="root" \ MYSQL_PASS="root" \ MYSQL_DB="pdns" \ MYSQL_DNSSEC="no" \ + MYSQL_VERSION="4.3.0" \ PGSQL_HOST="postgres" \ PGSQL_PORT="5432" \ PGSQL_USER="postgres" \ PGSQL_PASS="postgres" \ PGSQL_DB="pdns" \ - SQLITE_DB="pdns.sqlite3" + PGSQL_VERSION="4.3.0" \ + SQLITE_DB="pdns.sqlite3" \ + SQLITE_VERSION="4.3.1" \ + SCHEMA_VERSION_TABLE="_schema_version" EXPOSE 53/tcp 53/udp ADD pdns.conf /etc/pdns/ diff --git a/README.md b/README.md index 427e1a8..1dc430a 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ * Small Alpine based Image * MySQL (default), Postgres, SQLite and Bind backend included +* Automatic migration of database schema (for MySQL, Postgres and SQLite) * DNSSEC support optional * Automatic database initialization for MySQL, Postgres and SQLite * Latest PowerDNS version (if not pls file an issue) @@ -97,6 +98,10 @@ $ docker run --name pdns \ * `SQLITE_DB=/pdns.sqlite3` * DNSSEC is disabled by default, to enable use `DNSSEC=yes` * Want to disable database initialization? Use `AUTOCONF=false` + * Want to disable automatic migration of database schema? Use `AUTO_SCHEMA_MIGRATION=no` + * If this option is enabled afterwards on an existing installation, set `INITIAL_DB_VERSION=x.y.z` + where x.y.z is the version of the schema currently installed on the database. + This variable can be safely removed once the database has been upgraded for the first time. * Want to apply 12Factor-Pattern? Apply environment variables of the form `PDNS_$pdns-config-variable=$config-value`, like `PDNS_WEBSERVER=yes` * Want to use own config files? Mount a Volume to `/etc/pdns/conf.d` or simply overwrite `/etc/pdns/pdns.conf` * Use `TRACE=true` to debug the pdns config directives diff --git a/entrypoint.sh b/entrypoint.sh index e3abcba..13290dd 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -47,6 +47,7 @@ esac MYSQLCMD="mysql -h $MYSQL_HOST -u $MYSQL_USER -p$MYSQL_PASS -r -N" PGSQLCMD="psql --host=$PGSQL_HOST --username=$PGSQL_USER" +SQLITECMD="sqlite3 $PDNS_GSQLITE3_DATABASE" # wait for Database come ready isDBup () { @@ -89,6 +90,29 @@ case "$PDNS_LAUNCH" in if [ "$(echo "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = \"$MYSQL_DB\";" | $MYSQLCMD)" -le 1 ]; then echo Initializing Database cat /etc/pdns/sql/schema.mysql.sql | $MYSQLCMD + INITIAL_DB_VERSION=$MYSQL_VERSION + fi + if [ "$AUTO_SCHEMA_MIGRATION" == "yes" ]; then + # init version database if necessary + if [ "$(echo "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = \"$MYSQL_DB\" and table_name = \"$SCHEMA_VERSION_TABLE\";" | $MYSQLCMD)" -eq 0 ]; then + [ -z "$INITIAL_DB_VERSION" ] && >&2 echo "Error: INITIAL_DB_VERSION is required when you use AUTO_SCHEMA_MIGRATION for the first time" && exit 1 + echo "CREATE TABLE $SCHEMA_VERSION_TABLE (id INT AUTO_INCREMENT primary key NOT NULL, version VARCHAR(255) NOT NULL) Engine=InnoDB CHARACTER SET 'latin1';" | $MYSQLCMD + echo "INSERT INTO $SCHEMA_VERSION_TABLE (version) VALUES ('$INITIAL_DB_VERSION');" | $MYSQLCMD + echo "Initialized schema version to $INITIAL_DB_VERSION" + fi + # do the database upgrade + while true; do + current="$(echo "SELECT version FROM $SCHEMA_VERSION_TABLE ORDER BY id DESC LIMIT 1;" | $MYSQLCMD)" + if [ "$current" != "$MYSQL_VERSION" ]; then + filename=/etc/pdns/sql/${current}_to_*_schema.mysql.sql + echo "Applying Update $(basename $filename)" + $MYSQLCMD < $filename + current=$(basename $filename | sed -n 's/^[0-9.]\+_to_\([0-9.]\+\)_.*$/\1/p') + echo "INSERT INTO $SCHEMA_VERSION_TABLE (version) VALUES ('$current');" | $MYSQLCMD + else + break + fi + done fi ;; gpgsql) @@ -99,13 +123,60 @@ case "$PDNS_LAUNCH" in if [[ -z "$(printf '\dt' | $PGSQLCMD -qAt)" ]]; then echo Initializing Database cat /etc/pdns/sql/schema.pgsql.sql | $PGSQLCMD + INITIAL_DB_VERSION=$PGSQL_VERSION + fi + if [ "$AUTO_SCHEMA_MIGRATION" == "yes" ]; then + # init version database if necessary + if [[ -z "$(echo "SELECT to_regclass('public.$SCHEMA_VERSION_TABLE');" | $PGSQLCMD -qAt)" ]]; then + [ -z "$INITIAL_DB_VERSION" ] && >&2 echo "Error: INITIAL_DB_VERSION is required when you use AUTO_SCHEMA_MIGRATION for the first time" && exit 1 + echo "CREATE TABLE $SCHEMA_VERSION_TABLE (id SERIAL PRIMARY KEY, version VARCHAR(255) DEFAULT NULL)" | $PGSQLCMD + echo "INSERT INTO $SCHEMA_VERSION_TABLE (version) VALUES ('$INITIAL_DB_VERSION');" | $PGSQLCMD + echo "Initialized schema version to $INITIAL_DB_VERSION" + fi + # do the database upgrade + while true; do + current="$(echo "SELECT version FROM $SCHEMA_VERSION_TABLE ORDER BY id DESC LIMIT 1;" | $PGSQLCMD -qAt)" + if [ "$current" != "$PGSQL_VERSION" ]; then + filename=/etc/pdns/sql/${current}_to_*_schema.pgsql.sql + echo "Applying Update $(basename $filename)" + $PGSQLCMD < $filename + current=$(basename $filename | sed -n 's/^[0-9.]\+_to_\([0-9.]\+\)_.*$/\1/p') + echo "INSERT INTO $SCHEMA_VERSION_TABLE (version) VALUES ('$current');" | $PGSQLCMD + else + break + fi + done fi ;; gsqlite3) if [[ ! -f "$PDNS_GSQLITE3_DATABASE" ]]; then install -D -d -o pdns -g pdns -m 0755 $(dirname $PDNS_GSQLITE3_DATABASE) - cat /etc/pdns/sql/schema.sqlite3.sql | sqlite3 $PDNS_GSQLITE3_DATABASE + cat /etc/pdns/sql/schema.sqlite3.sql | $SQLITECMD chown pdns:pdns $PDNS_GSQLITE3_DATABASE + INITIAL_DB_VERSION=$SQLITE_VERSION + fi + if [ "$AUTO_SCHEMA_MIGRATION" == "yes" ]; then + # init version database if necessary + if [[ "$(echo "SELECT count(*) FROM sqlite_master WHERE type='table' AND name='$SCHEMA_VERSION_TABLE';" | $SQLITECMD)" -eq 0 ]]; then + [ -z "$INITIAL_DB_VERSION" ] && >&2 echo "Error: INITIAL_DB_VERSION is required when you use AUTO_SCHEMA_MIGRATION for the first time" && exit 1 + echo "CREATE TABLE $SCHEMA_VERSION_TABLE (id INTEGER PRIMARY KEY, version VARCHAR(255) NOT NULL)" | $SQLITECMD + echo "INSERT INTO $SCHEMA_VERSION_TABLE (version) VALUES ('$INITIAL_DB_VERSION');" | $SQLITECMD + echo "Initialized schema version to $INITIAL_DB_VERSION" + fi + # do the database upgrade + while true; do + current="$(echo "SELECT version FROM $SCHEMA_VERSION_TABLE ORDER BY id DESC LIMIT 1;" | $SQLITECMD)" + if [ "$current" != "$SQLITE_VERSION" ]; then + filename=/etc/pdns/sql/${current}_to_*_schema.sqlite3.sql + echo "Applying Update $(basename $filename)" + $SQLITECMD < $filename + current=$(basename $filename | sed -n 's/^[0-9.]\+_to_\([0-9.]\+\)_.*$/\1/p') + echo "INSERT INTO $SCHEMA_VERSION_TABLE (version) VALUES ('$current');" | $SQLITECMD + else + break + fi + done + fi ;; esac From 4d79e878f04c212a798a67349ec7ccc5c9fea74c Mon Sep 17 00:00:00 2001 From: Antoine Millet Date: Sun, 29 Nov 2020 16:45:08 +0100 Subject: [PATCH 11/11] Cleaned up default configuration file --- entrypoint.sh | 2 +- pdns.conf | 601 +------------------------------------------------- 2 files changed, 8 insertions(+), 595 deletions(-) diff --git a/entrypoint.sh b/entrypoint.sh index 13290dd..660a767 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -188,7 +188,7 @@ printenv | grep ^PDNS_ | cut -f2- -d_ | while read var; do var="${var%%=*}" var="$(echo $var | sed -e 's/_/-/g' | tr '[:upper:]' '[:lower:]')" [[ -z "$TRACE" ]] || echo "$var=$val" - sed -r -i "s#^[# ]*$var=.*#$var=$val#g" /etc/pdns/pdns.conf + (grep -qE "^[# ]*$var=.*" /etc/pdns/pdns.conf && sed -r -i "s#^[# ]*$var=.*#$var=$val#g" /etc/pdns/pdns.conf) || echo "$var=$val" >> /etc/pdns/pdns.conf done # environment hygiene diff --git a/pdns.conf b/pdns.conf index 5ead7e4..58e8530 100644 --- a/pdns.conf +++ b/pdns.conf @@ -1,595 +1,8 @@ -# Autogenerated configuration file template -################################# -# 8bit-dns Allow 8bit dns queries -# -# 8bit-dns=no - -################################# -# allow-axfr-ips Allow zonetransfers only to these subnets -# -# allow-axfr-ips=127.0.0.0/8,::1 - -################################# -# allow-dnsupdate-from A global setting to allow DNS updates from these IP ranges. -# -# allow-dnsupdate-from=127.0.0.0/8,::1 - -################################# -# allow-notify-from Allow AXFR NOTIFY from these IP ranges. If empty, drop all incoming notifies. -# -# allow-notify-from=0.0.0.0/0,::/0 - -################################# -# allow-recursion List of subnets that are allowed to recurse -# -# allow-recursion=0.0.0.0/0 - -################################# -# allow-unsigned-notify Allow unsigned notifications for TSIG secured domains -# -# allow-unsigned-notify=yes - -################################# -# allow-unsigned-supermaster Allow supermasters to create zones without TSIG signed NOTIFY -# -# allow-unsigned-supermaster=yes - -################################# -# also-notify When notifying a domain, also notify these nameservers -# -# also-notify= - -################################# -# any-to-tcp Answer ANY queries with tc=1, shunting to TCP -# -# any-to-tcp=yes - -################################# -# api Enable/disable the REST API -# -# api=no - -################################# -# api-key Static pre-shared authentication key for access to the REST API -# -# api-key= - -################################# -# api-logfile Location of the server logfile (used by the REST API) -# -# api-logfile=/var/log/pdns.log - -################################# -# api-readonly Disallow data modification through the REST API when set -# -# api-readonly=no - -################################# -# cache-ttl Seconds to store packets in the PacketCache -# -# cache-ttl=20 - -################################# -# carbon-interval Number of seconds between carbon (graphite) updates -# -# carbon-interval=30 - -################################# -# carbon-ourname If set, overrides our reported hostname for carbon stats -# -# carbon-ourname= - -################################# -# carbon-server If set, send metrics in carbon (graphite) format to this server -# -# carbon-server= - -################################# -# chroot If set, chroot to this directory for more security -# -# chroot= - -################################# -# config-dir Location of configuration directory (pdns.conf) -# -# config-dir=/etc/pdns - -################################# -# config-name Name of this virtual configuration - will rename the binary image -# -# config-name= - -################################# -# control-console Debugging switch - don't use -# -# control-console=no - -################################# -# daemon Operate as a daemon -# -daemon=no - -################################# -# default-ksk-algorithms Default KSK algorithms -# -# default-ksk-algorithms=ecdsa256 - -################################# -# default-ksk-size Default KSK size (0 means default) -# -# default-ksk-size=0 - -################################# -# default-soa-edit Default SOA-EDIT value -# -# default-soa-edit= - -################################# -# default-soa-edit-signed Default SOA-EDIT value for signed zones -# -# default-soa-edit-signed= - -################################# -# default-soa-mail mail address to insert in the SOA record if none set in the backend -# -# default-soa-mail= - -################################# -# default-soa-name name to insert in the SOA record if none set in the backend -# -# default-soa-name=a.misconfigured.powerdns.server - -################################# -# default-ttl Seconds a result is valid if not set otherwise -# -# default-ttl=3600 - -################################# -# default-zsk-algorithms Default ZSK algorithms -# -# default-zsk-algorithms= - -################################# -# default-zsk-size Default ZSK size (0 means default) -# -# default-zsk-size=0 - -################################# -# direct-dnskey Fetch DNSKEY RRs from backend during DNSKEY synthesis -# -# direct-dnskey=no - -################################# -# disable-axfr Disable zonetransfers but do allow TCP queries -# -# disable-axfr=no - -################################# -# disable-axfr-rectify Disable the rectify step during an outgoing AXFR. Only required for regression testing. -# -# disable-axfr-rectify=no - -################################# -# disable-syslog Disable logging to syslog, useful when running inside a supervisor that logs stdout -# -disable-syslog=yes - -################################# -# disable-tcp Do not listen to TCP queries -# -# disable-tcp=no - -################################# -# distributor-threads Default number of Distributor (backend) threads to start -# -# distributor-threads=3 - -################################# -# dname-processing If we should support DNAME records -# -# dname-processing=no - -################################# -# dnssec-key-cache-ttl Seconds to cache DNSSEC keys from the database -# -# dnssec-key-cache-ttl=30 - -################################# -# dnsupdate Enable/Disable DNS update (RFC2136) support. Default is no. -# -# dnsupdate=no - -################################# -# do-ipv6-additional-processing Do AAAA additional processing -# -# do-ipv6-additional-processing=yes - -################################# -# domain-metadata-cache-ttl Seconds to cache domain metadata from the database -# -# domain-metadata-cache-ttl=60 - -################################# -# edns-subnet-processing If we should act on EDNS Subnet options -# -# edns-subnet-processing=no - -################################# -# entropy-source If set, read entropy from this file -# -# entropy-source=/dev/urandom - -################################# -# experimental-lua-policy-script Lua script for the policy engine -# -# experimental-lua-policy-script= - -################################# -# forward-dnsupdate A global setting to allow DNS update packages that are for a Slave domain, to be forwarded to the master. -# -# forward-dnsupdate=yes - -################################# -# guardian Run within a guardian process - +config-dir=/etc/pdns +include-dir=/etc/pdns/conf.d guardian=yes - -################################# -# include-dir Include *.conf files from this directory -# -# include-dir= - -################################# -# launch Which backends to launch and order to query them in -# -launch=bind - -################################# -# load-modules Load this module - supply absolute or relative path -# -# load-modules= - -################################# -# local-address Local IP addresses to which we bind -# -# local-address=0.0.0.0 - -################################# -# local-address-nonexist-fail Fail to start if one or more of the local-address's do not exist on this server -# -# local-address-nonexist-fail=yes - -################################# -# local-ipv6 Local IP address to which we bind -# -# local-ipv6=:: - -################################# -# local-ipv6-nonexist-fail Fail to start if one or more of the local-ipv6 addresses do not exist on this server -# -# local-ipv6-nonexist-fail=yes - -################################# -# local-port The port on which we listen -# -# local-port=53 - -################################# -# log-dns-details If PDNS should log DNS non-erroneous details -# -# log-dns-details=no - -################################# -# log-dns-queries If PDNS should log all incoming DNS queries -# -# log-dns-queries=no - -################################# -# logging-facility Log under a specific facility -# -# logging-facility= - -################################# -# loglevel Amount of logging. Higher is more. Do not set below 3 -# -# loglevel=4 - -################################# -# lua-prequery-script Lua script with prequery handler (DO NOT USE) -# -# lua-prequery-script= - -################################# -# master Act as a master -# -# master=no - -################################# -# max-cache-entries Maximum number of cache entries -# -# max-cache-entries=1000000 - -################################# -# max-ent-entries Maximum number of empty non-terminals in a zone -# -# max-ent-entries=100000 - -################################# -# max-nsec3-iterations Limit the number of NSEC3 hash iterations -# -# max-nsec3-iterations=500 - -################################# -# max-queue-length Maximum queuelength before considering situation lost -# -# max-queue-length=5000 - -################################# -# max-signature-cache-entries Maximum number of signatures cache entries -# -# max-signature-cache-entries= - -################################# -# max-tcp-connections Maximum number of TCP connections -# -# max-tcp-connections=20 - -################################# -# module-dir Default directory for modules -# -# module-dir=/usr/lib/pdns - -################################# -# negquery-cache-ttl Seconds to store negative query results in the QueryCache -# -# negquery-cache-ttl=60 - -################################# -# no-shuffle Set this to prevent random shuffling of answers - for regression testing -# -# no-shuffle=off - -################################# -# non-local-bind Enable binding to non-local addresses by using FREEBIND / BINDANY socket options -# -# non-local-bind=no - -################################# -# only-notify Only send AXFR NOTIFY to these IP addresses or netmasks -# -# only-notify=0.0.0.0/0,::/0 - -################################# -# out-of-zone-additional-processing Do out of zone additional processing -# -# out-of-zone-additional-processing=yes - -################################# -# outgoing-axfr-expand-alias Expand ALIAS records during outgoing AXFR -# -# outgoing-axfr-expand-alias=no - -################################# -# overload-queue-length Maximum queuelength moving to packetcache only -# -# overload-queue-length=0 - -################################# -# prevent-self-notification Don't send notifications to what we think is ourself -# -# prevent-self-notification=yes - -################################# -# query-cache-ttl Seconds to store query results in the QueryCache -# -# query-cache-ttl=20 - -################################# -# query-local-address Source IP address for sending queries -# -# query-local-address=0.0.0.0 - -################################# -# query-local-address6 Source IPv6 address for sending queries -# -# query-local-address6=:: - -################################# -# query-logging Hint backends that queries should be logged -# -# query-logging=no - -################################# -# queue-limit Maximum number of milliseconds to queue a query -# -# queue-limit=1500 - -################################# -# receiver-threads Default number of receiver threads to start -# -# receiver-threads=1 - -################################# -# recursive-cache-ttl Seconds to store packets for recursive queries in the PacketCache -# -# recursive-cache-ttl=10 - -################################# -# recursor If recursion is desired, IP address of a recursing nameserver -# -# recursor=no - -################################# -# retrieval-threads Number of AXFR-retrieval threads for slave operation -# -# retrieval-threads=2 - -################################# -# reuseport Enable higher performance on compliant kernels by using SO_REUSEPORT allowing each receiver thread to open its own socket -# -# reuseport=no - -################################# -# security-poll-suffix Domain name from which to query security update notifications -# -# security-poll-suffix=secpoll.powerdns.com. - -################################# -# server-id Returned when queried for 'server.id' TXT or NSID, defaults to hostname - disabled or custom -# -# server-id= - -################################# -# setgid If set, change group id to this gid for more security -# -# setgid= - -################################# -# setuid If set, change user id to this uid for more security -# -# setuid= - -################################# -# signing-threads Default number of signer threads to start -# -# signing-threads=3 - -################################# -# slave Act as a slave -# -# slave=no - -################################# -# slave-cycle-interval Schedule slave freshness checks once every .. seconds -# -# slave-cycle-interval=60 - -################################# -# slave-renotify If we should send out notifications for slaved updates -# -# slave-renotify=no - -################################# -# soa-expire-default Default SOA expire -# -# soa-expire-default=604800 - -################################# -# soa-minimum-ttl Default SOA minimum ttl -# -# soa-minimum-ttl=3600 - -################################# -# soa-refresh-default Default SOA refresh -# -# soa-refresh-default=10800 - -################################# -# soa-retry-default Default SOA retry -# -# soa-retry-default=3600 - -################################# -# socket-dir Where the controlsocket will live, /var/run when unset and not chrooted -# -# socket-dir= - -################################# -# tcp-control-address If set, PowerDNS can be controlled over TCP on this address -# -# tcp-control-address= - -################################# -# tcp-control-port If set, PowerDNS can be controlled over TCP on this address -# -# tcp-control-port=53000 - -################################# -# tcp-control-range If set, remote control of PowerDNS is possible over these networks only -# -# tcp-control-range=127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10 - -################################# -# tcp-control-secret If set, PowerDNS can be controlled over TCP after passing this secret -# -# tcp-control-secret= - -################################# -# traceback-handler Enable the traceback handler (Linux only) -# -# traceback-handler=yes - -################################# -# trusted-notification-proxy IP address of incoming notification proxy -# -# trusted-notification-proxy= - -################################# -# udp-truncation-threshold Maximum UDP response size before we truncate -# -# udp-truncation-threshold=1680 - -################################# -# version-string PowerDNS version in packets - full, anonymous, powerdns or custom -# -# version-string=full - -################################# -# webserver Start a webserver for monitoring -# -# webserver=no - -################################# -# webserver-address IP Address of webserver to listen on -# -# webserver-address=127.0.0.1 - -################################# -# webserver-allow-from Webserver access is only allowed from these subnets -# -# webserver-allow-from=0.0.0.0/0,::/0 - -################################# -# webserver-password Password required for accessing the webserver -# -# webserver-password= - -################################# -# webserver-port Port of webserver to listen on -# -# webserver-port=8081 - -################################# -# webserver-print-arguments If the webserver should print arguments -# -# webserver-print-arguments=no - -################################# -# write-pid Write a PID file -# -# write-pid=yes - -################################# -# xfr-max-received-mbytes Maximum number of megabytes received from an incoming XFR -# -# xfr-max-received-mbytes=100 - -# launch Which backends to launch and order to query them in -#gmysql-host=mysql -#gmysql-port=3306 -#gmysql-dbname=pdns -#gmysql-user=root -#gmysql-password=root -#gmysql-dnssec=no - -#gpgsql-host=postgres -#gpgsql-port=5432 -#gpgsql-dbname=pdns -#gpgsql-user=postgres -#gpgsql-password=postgres -#gpgsql-dnssec=no - -#gsqlite3-database=/pdns.sqlite3 -#gsqlite3-pragma-synchronous=1 -#gsqlite3-pragma-foreign-keys=1 -#gsqlite3-dnssec=no +loglevel=3 +setgid=pdns +setuid=pdns +socket-dir=/var/run +version-string=anonymous