Commit c965227f authored by Thomas Gambier's avatar Thomas Gambier 🚴🏼

powerdns: target Python 3 and upgrade to 4.2.1

This MR includes the following steps:
1. Target Python 3
2. Upgrade powerdns from version 3.3.1 to version 4.2.1 --- which also means...
3. Rework the configuration to support the [new GeoIP backend config format](https://doc.powerdns.com/authoritative/backends/geoip.html)

See the commit messages for more detail.

Note: EDNS Client Subnet extension is enabled.

See merge request nexedi/slapos!764
parents 53331088 32df49b3
Pipeline #10364 failed with stage
......@@ -2,33 +2,42 @@
extends =
../autoconf/buildout.cfg
../automake/buildout.cfg
../bison/buildout.cfg
../flex/buildout.cfg
../git/buildout.cfg
../boost-lib/buildout.cfg
../libtool/buildout.cfg
../make/buildout.cfg
../mariadb/buildout.cfg
../openssl/buildout.cfg
../pkgconfig/buildout.cfg
../ragel/buildout.cfg
../zlib/buildout.cfg
# For geoip backend
# https://doc.powerdns.com/authoritative/backends/geoip.html
../geoip2/buildout.cfg
../yaml-cpp/buildout.cfg
parts =
powerdns
[powerdns]
recipe = slapos.recipe.cmmi
url = http://downloads.powerdns.com/releases/pdns-3.3.1.tar.gz
md5sum = 074e2ff211fd12ecad25b5c1cc190dd4
url = http://downloads.powerdns.com/releases/pdns-4.2.1.tar.bz2
md5sum = b5f3998a3bc438b905c72c0473408839
configure-options =
--prefix=${buildout:parts-directory}/${:_buildout_section_name_}
--with-boost=${boost-lib:location}
--with-modules="geo"
--with-libcrypto=${openssl:location}
--with-modules="geoip"
--with-dynmodules=""
--without-lua
--disable-lua-records
pkg_config_depends = ${yaml-cpp:location}/lib/pkgconfig
environment =
PATH=${make:location}/bin:${libtool:location}/bin:${pkgconfig:location}/bin:${bison:location}/bin:${flex:location}/bin:${git:location}/bin:${ragel:location}/bin:%(PATH)s
LDFLAGS=-L${boost-lib:location}/lib -Wl,-rpath=${boost-lib:location}/lib -L${zlib:location}/lib -Wl,-rpath -Wl,${zlib:location}/lib -lz
CPPFLAGS=-I${boost-lib:location}/include
PATH=${autoconf:location}/bin:${automake:location}/bin:${libmaxminddb:location}/bin:${libtool:location}/bin:${make:location}/bin:${pkgconfig:location}/bin:%(PATH)s
LDFLAGS=-L${boost-lib:location}/lib -Wl,-rpath=${boost-lib:location}/lib -L${libmaxminddb:location}/lib -Wl,-rpath=${libmaxminddb:location}/lib -L${openssl:location}/lib -Wl,-rpath=${openssl:location}/lib -L${yaml-cpp:location}/lib -Wl,-rpath=${yaml-cpp:location}/lib -L${zlib:location}/lib -Wl,-rpath=${zlib:location}/lib
CPPFLAGS=-I${boost-lib:location}/include -I${libmaxminddb:location}/include -I${yaml-cpp:location}/include
PKG_CONFIG_PATH=${:pkg_config_depends}
# XXX: Override the default value "-Llib -lyaml-cpp"; "-Llib" is a problem
YAML_LIBS = -lyaml-cpp
make-options =
LIBTOOL=libtool
make-target =
install
[buildout]
extends =
../cmake/buildout.cfg
parts =
yaml-cpp
[yaml-cpp]
recipe = slapos.recipe.cmmi
shared = true
url = https://github.com/jbeder/yaml-cpp/archive/yaml-cpp-0.6.3.tar.gz
md5sum = b45bf1089a382e81f6b661062c10d0c2
location = @@LOCATION@@
configure-command =
mkdir build && cd build && \
${cmake:location}/bin/cmake \
-DYAML_BUILD_SHARED_LIBS=ON \
-DCMAKE_INSTALL_PREFIX=${:location} \
..
make-options = -C build
......@@ -14,24 +14,24 @@
# not need these here).
[template]
filename = instance.cfg
md5sum = da8be58db4255c07750f7a7583eab3ca
md5sum = fddea033e1aa9d6147a1a47bd7cc4b62
[template-powerdns]
filename = instance-powerdns.cfg
md5sum = 681cd9564e491d1f7b7ccb810f8ca7df
md5sum = 2adb91323d60fc350f52910a3257d4a7
[template-pdns-configuration]
_update_hash_filename_ = template/pdns.conf.jinja2
md5sum = 7934b7037344678eff3031e1e73e0bb2
md5sum = e45d72de87b4adb89c195ba463be4077
[template-dns-replicate]
_update_hash_filename_ = instance-powerdns-replicate.cfg.jinja2
md5sum = 46acd4ed071df8d7139dcd0434be42eb
md5sum = a23e241a236f90ae1afbb5bd5ba0b32d
[iso-list]
_update_hash_filename_ = template/zz.countries.nexedi.dk.rbldnsd
md5sum = c4dc8c141d81b92d92cdb82ca67a13ee
[template-cdn-conf]
_update_hash_filename_ = template/cdn.conf.in
md5sum = 29c29f93b3b0bd2f71f86f7b337e4543
[template-zones-file]
_update_hash_filename_ = template/zones-file.yml.jinja2
md5sum = c820a4f53c3e7706f51a5e0be3a8cf74
......@@ -60,7 +60,7 @@ context =
<= replicate
name = {{dns_name}}
{% set state_key = "-dns-%s-state" % i %}
{% if slapparameter_dict.has_key(state_key) %}
{% if state_key in slapparameter_dict %}
state = {{ slapparameter_dict.pop(state_key) }}
{% endif%}
config-zone = {{ zone }}
......@@ -95,7 +95,7 @@ monitor-url-list +=
<= slap-connection
recipe = slapos.cookbook:requestoptional
{% set dns_software_url_key = "-dns-software-release-url" %}
{% if slapparameter_dict.has_key(dns_software_url_key) %}
{% if dns_software_url_key in slapparameter_dict %}
software-url = {{ slapparameter_dict.pop(dns_software_url_key) }}
{% else %}
software-url = ${slap-connection:software-release-url}
......@@ -104,7 +104,7 @@ software-type = {{dns_type}}
return = private-ipv4 public-ipv4 slave-instance-information-list monitor-base-url
config-server-admin = {{ server_admin }}
config-ns-record = {{ ns_record }}
{% for parameter, value in slapparameter_dict.iteritems() -%}
{% for parameter, value in slapparameter_dict.items() -%}
config-{{parameter}} = {{ value }}
{% endfor -%}
config-{{ slave_list_name }} = {{ json_module.dumps(slave_instance_list) }}
......@@ -151,7 +151,7 @@ key_file = ${slap-connection:key-file}
cert_file = ${slap-connection:cert-file}
[slap-parameter]
slave_instance_list =
-dns-quantity = 1
-dns-type = single-default
{% for k, v in slapparameter_dict.items() -%}
{{ k }} = {{ v }}
{% endfor -%}
{%- endif %}
{% if slap_software_type in software_type -%}
{% set part_list = [] %}
# Create all needed directories
[directory]
......@@ -63,13 +62,12 @@ socket-directory = $${pdns-directory:socket}
webserver-port = 8088
[geo]
ip-map-zonefile = ${iso-list:target}
geo-maps = $${pdns-directory:geo-maps}
zones-file = $${zones-file-template:rendered}
database = ${geolite2-country:location}/GeoLite2-Country.mmdb
[pdns-directory]
recipe = slapos.cookbook:mkdirectory
configuration = $${directory:etc}/pdns
geo-maps = $${:configuration}/geo-maps
socket = $${directory:run}/pdns-socket
[pdns-configuration-template]
......@@ -80,6 +78,39 @@ extra-context =
section pdns pdns
section geo geo
[asia]
japan = jp
hong-kong = hk
china-telecom = cn-t
china-unicom = cn-u
china-mobile = cn-m
west-asia = ae af am az bh cc cy ge il iq ir jo kg kw kz lb om pk qa ru sa sy tj tm tr uz ye
east-asia = bn bt cx id in io kh kp kr la lk mm mn mo mv my np ph sg th to tw vn
[china]
recipe = slapos.recipe.build
iso-list = ${iso-list:target}
init =
import re
ip_split = []
match = re.compile(r"(.*) :.*:(cn-\w)\n").fullmatch
with open(options["iso-list"]) as f:
for line in f:
m = match(line)
if m is None:
continue
ip_split.append(m.groups())
options["ip-split"] = ip_split
[zones-file-template]
< = jinja2-template-base
template = ${template-zones-file:target}
extensions = jinja2.ext.do
rendered = $${pdns-directory:configuration}/zones-file.yml
extra-context =
section asia asia
key china china:ip-split
# Executables
[pdns-server]
recipe = slapos.cookbook:wrapper
......@@ -117,29 +148,6 @@ monitor-url = $${monitor-publish-parameters:monitor-url}
monitor-user = $${monitor-publish-parameters:monitor-user}
monitor-password = $${monitor-publish-parameters:monitor-password}
#####################
# Power DNS Slave configuration
#
{% set slave_instance_list = json_module.loads(slapparameter_dict.get('extra_slave_instance_list', '[]')) %}
# Iter through slave list to prepare configuration
{% for slave in slave_instance_list %}
{% if 'record' in slave and 'origin' in slave and 'default' in slave %}
{% set slave_reference = slave.get('slave_reference') %}
{% set slave_section_name = 'map-configuration-%s' % slave_reference %}
{% do part_list.append(slave_section_name) %}
[{{ slave_section_name }}]
< = jinja2-template-base
template = ${template-cdn-conf:target}
rendered = $${geo:geo-maps}/{{ slave_reference }}
configuration = {{ json_module.dumps(slave) }}
extra-context =
key json_cdn :configuration
{% endif %}
{% endfor %}
####################
[buildout]
parts =
pdns-configuration-template
......@@ -149,9 +157,6 @@ parts =
pdns-promise-listen-port
monitor-base
publish-connection-informations
{% for part in part_list %}
{{ ' %s' % part }}
{% endfor %}
extends = ${monitor-template:output}
......
......@@ -8,10 +8,12 @@ offline = true
[switch-softwaretype]
recipe = slapos.cookbook:softwaretype
default = $${dynamic-powerdns-replicate:rendered}
single-default = $${dynamic-template-powerdns:rendered}
recipe = slapos.cookbook:switch-softwaretype
default = dynamic-powerdns-replicate:rendered
single-default = dynamic-template-powerdns:rendered
# BBB
RootSoftwareInstance = $${:default}
[jinja2-template-base]
recipe = slapos.recipe.template:jinja2
......@@ -21,9 +23,9 @@ context =
import json_module json
key eggs_directory buildout:eggs-directory
key develop_eggs_directory buildout:develop-eggs-directory
key slap_software_type slap-parameters:slap-software-type
key slapparameter_dict slap-parameters:configuration
key slave_instance_list slap-parameters:slave-instance-list
key slap_software_type slap-configuration:slap-software-type
key slapparameter_dict slap-configuration:configuration
key slave_instance_list slap-configuration:slave-instance-list
$${:extra-context}
[dynamic-template-powerdns]
......@@ -38,14 +40,14 @@ extra-context =
[dynamic-powerdns-replicate]
< = jinja2-template-base
template = ${template-dns-replicate:target}
filename = instance-apache-replicate.cfg
filename = instance-powerdns-replicate.cfg
extensions = jinja2.ext.do
extra-context =
# Must match the key id in [switch-softwaretype] which uses this section.
raw software_type RootSoftwareInstance-default
raw template_monitor ${monitor2-template:rendered}
[slap-parameters]
[slap-configuration]
recipe = slapos.cookbook:slapconfiguration
computer = $${slap-connection:computer-id}
partition = $${slap-connection:partition-id}
......
......@@ -10,12 +10,12 @@
},
"origin": {
"title": "Origin",
"description": "Used to qualify RR in the configuration. i.e.: if your origin is a.example.com and the RR for Europe is 'eu' the european clients will use eu.a.exmple.com",
"description": "Used to qualify RR in the configuration. i.e.: if your origin is a.example.com and the RR for Europe is 'eu' the european clients will use eu.a.example.com",
"type": "string"
},
"default": {
"title": "Default RR",
"description": "Defautl record to use when the ip is not regognized",
"description": "Default record to use when the ip is not recognized",
"type": "string"
},
"europe": {
......
......@@ -10,10 +10,8 @@ parts =
slapos-cookbook
eggs
[gcc]
# For old version of PowerDNS and Ragel.
part = gcc-5.5
max_version = 6
[python]
part = python3
[eggs]
recipe = zc.recipe.egg
......@@ -47,7 +45,7 @@ recipe = slapos.recipe.build:download
url = ${:_profile_base_location_}/${:_update_hash_filename_}
mode = 0644
[template-cdn-conf]
[template-zones-file]
recipe = slapos.recipe.build:download
url = ${:_profile_base_location_}/${:_update_hash_filename_}
mode = 0644
......
This diff is collapsed.
......@@ -31,7 +31,8 @@ cache-ttl=0
# things are working. :)
log-dns-details=yes
log-dns-queries=yes
log-failed-updates=yes
# https://github.com/PowerDNS/pdns/commit/df9d980
# log-failed-updates=yes
loglevel=4
# This disables wildcards which is more efficient. geobackend doesn't use
......@@ -40,52 +41,11 @@ loglevel=4
# wildcards=no
# The geobackend
launch=geo
launch=geoip
# The zone that your geo-balanced RR is inside of. The whole zone has to be
# delegated to the PowerDNS backend, so you will generally want to make up some
# subzone of your main zone. We chose "geo.blitzed.org".
#
geo-zone={{ slapparameter_dict.get('zone', 'example.com') }}
# The only parts of the SOA for "geo.blitzed.org" that apply here are the
# master server name and the contact address.
geo-soa-values={{ slapparameter_dict.get('soa', 'ns0.example.com,admin@example.com') }}
# List of NS records of the PowerDNS servers that are authoritative for your
# GLB zone.
geo-ns-records={{ slapparameter_dict.get('ns-record', 'ns0.example.com,ns1.example.com') }}
# The TTL of the CNAME records that geobackend will return. Since the same
# resolver will always get the same CNAME (apart from if the director-map
# changes) it is safe to return a reasonable TTL, so if you leave this
# commented then a sane default will be chosen.
#geo-ttl=3600
# The TTL of the NS records that will be returned. Leave this commented if you
# don't understand.
#geo-ns-ttl=86400
# This is the real guts of the data that drives this backend. This is a DNS
# zone file for RBLDNSD, a nameserver specialised for running large DNS zones
# typical of DNSBLs and such. We choose it for our data because it is easier
# to parse than the BIND-format one.
#
# Anyway, it comes from http://countries.nerd.dk/more.html - there are details
# there for how to rsync your own copy. You'll want to do that regularly,
# every couple of days maybe. We believe the nerd.dk guys take the netblock
# info from Regional Internet Registries (RIRs) like RIPE, ARIN, APNIC. From
# that they build a big zonefile of IP/prefixlen -> ISO-country-code mappings.
geo-ip-map-zonefile={{ geo.get('ip-map-zonefile') }}
edns-subnet-processing=yes
# And finally this last directive tells the geobackend where to find the map
# files that say a) which RR to answer for, and b) what actual resource record
# to return for each ISO country code. The setting here is a comma-separated
# list of paths, each of which may either be a single map file or a directory
# that will contain map files. If you are only ever going to serve one RR then
# a single file is probably better, but if you're going to serve many then a
# directory would probably be better. The rest of this documentation will
# assume you chose a directory.
geo-maps={{ geo.get('geo-maps') }}
geoip-database-files={{ geo['database'] }}
geoip-zones-file={{ geo['zones-file'] }}
# -------------------------------------------------------------------------
\ No newline at end of file
# See https://doc.powerdns.com/authoritative/backends/geoip.html
{%- set slave_instance_list = json_module.loads(slapparameter_dict.get('extra_slave_instance_list', '[]')) %}
{%- set zone = slapparameter_dict.get('zone', 'example.com') %}
{%- macro disambiguate_domain_name(a, b) %}
{#- See http://www.dns-sd.org/trailingdotsindomainnames.html #}
{%- if a.endswith('.') %}
{{- a[:-1] }}
{%- else %}
{{- a }}.{{ b }}
{%- endif %}
{%- endmacro %}
domains:
- domain: {{ zone }}
# TODO: what value for ttl?
ttl: 300
# Note: For each domain, one record of the domain name MUST exist with a soa record.
records:
{{ zone }}:
- soa: {{ slapparameter_dict.get('soa', 'ns0.example.com,admin@example.com').replace(',', ' ') }}
{%- for ns in slapparameter_dict.get('ns-record', 'ns0.example.com,ns1.example.com').split(',') %}
- ns: {{ ns }}
{%- endfor %}
{#- Split the world the way we prefer. 'GeoLite2-Country.mmdb' divides the
world into 7 continents: Oceania, Asia, Europe, South America,
North America, Africa and Antarctica. However, we also want a more
fine-grained division for Asia, i.e. West/East, China, Hong-Kong and
Japan. #}
{%- set world_split = {
"continent": {
"eu": "europe",
"af": "africa",
"sa": "south-america",
"na": "north-america",
"oc": "oceania",
},
"country": {}} %}
{%- for region, codes in asia.items() %}
{%- for country_code in codes.split() %}
{%- do world_split["country"].__setitem__(country_code, region) %}
{%- endfor %}
{%- endfor %}
{%- for slave in slave_instance_list %}
{#- Set the RR to use for each region, as described in
'slave-instance-powerdns-input-schema.json' #}
{%- set rr_dict = {} %}
{%- for region, default_rr in {"europe": "eu",
"africa": "af",
"south-america": "sa",
"north-america": "na",
"china-telecom": "cn-t",
"china-unicom": "cn-u",
"china-mobile": "cn-m",
"japan": "jp",
"hong-kong": "hk",
"east-asia": "as",
"west-asia": "eu",
"oceania": "oc"}.items() %}
{%- do rr_dict.__setitem__(region, slave.get(region, default_rr)) %}
{%- endfor %}
{#- 'code2region' maps an ISO3166 country/continent code (i.e. the client
origin) to a geographical region. The latter is then used to find the
right RR (thanks to 'rr_dict') #}
{%- for placeholder, code2region in world_split.items() %}
{%- for code, region in code2region.items() %}
{%- set origin = slave['origin'] %}
{{ code }}.{{ placeholder }}.{{ origin }}:
- cname: {{ disambiguate_domain_name(rr_dict[region], origin) }}
{%- endfor %}
{%- endfor %}
{%- endfor %}
services:
{%- for slave in slave_instance_list %}
{%- set origin = slave['origin'] %}
{{ disambiguate_domain_name(slave['record'], zone) }}:
{#- Note: Placeholders (i.e. "country." and "continent.") are used to avoid
possible name collisions, e.g.:
- %cc for American Samoa is 'as'
- %cn for Asia is also 'as' #}
default: ['%cc.country.{{ origin }}', '%cn.continent.{{ origin }}', '{{ disambiguate_domain_name(slave['default'], origin) }}']
# Split China's ip addresses according to ISP
{%- for ip_range, country_code in china %}
{{ ip_range }}: {{ country_code }}.country.{{ origin }}
{%- endfor %}
{%- endfor %}
......@@ -13,3 +13,4 @@ eggs -=
[template]
extra =
${slapos.test.monitor-setup:setup}
${slapos.test.powerdns-setup:setup}
......@@ -249,7 +249,6 @@ extra =
${slapos.test.htmlvalidatorserver-setup:setup}
${slapos.test.slapos-master-setup:setup}
${slapos.test.plantuml-setup:setup}
${slapos.test.powerdns-setup:setup}
${slapos.test.proftpd-setup:setup}
${slapos.test.re6stnet-setup:setup}
${slapos.test.seleniumserver-setup:setup}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment