from ipaddress import IPv4Address, IPv6Address, ip_address from bundlewrap.metadata import atomic defaults = { 'apt': { 'packages': { 'pdns-server': {}, 'pdns-tools': {}, 'pdns-backend-bind': {}, 'pdns-backend-pgsql': {}, }, }, 'icinga2_api': { 'powerdns': { 'services': { 'POWERDNS PROCESS': { 'command_on_monitored_host': '/usr/lib/nagios/plugins/check_procs -C pdns_server -c 1:', 'vars.notification.mail': True, 'vars.notification.sms': True, }, }, }, }, 'powerdns': { 'api_key': repo.vault.password_for('{} powerdns api'.format(node.name)), }, 'postgresql': { 'roles': { 'powerdns': { 'password': repo.vault.password_for('{} postgresql powerdns'.format(node.name)), }, }, 'databases': { 'powerdns': { 'owner': 'powerdns', }, }, }, } if node.has_bundle('telegraf'): defaults['telegraf'] = { 'input_plugins': { 'builtin': { 'powerdns': [{ 'unix_sockets': [ '/var/run/pdns/pdns.controlsocket', ], }], }, }, 'additional_groups': { 'pdns', }, } @metadata_reactor.provides( 'icinga2_api/powerdns/services', ) def monitoring_for_primary_nameserver(metadata): if metadata.get('powerdns/is_secondary', False): return {} return { 'icinga2_api': { 'powerdns': { 'services': { 'POWERDNS WEB INTERFACE': { 'command_on_monitored_host': '/usr/local/share/icinga/plugins/check_http_url_for_string http://localhost:8081/ "PowerDNS"', }, }, }, }, } @metadata_reactor.provides( 'powerdns/my_secondary_servers', ) def get_ips_of_secondary_nameservers(metadata): if metadata.get('powerdns/is_secondary', False): return {} ips = set() for rnode in repo.nodes_in_group('dns'): if rnode.metadata.get('powerdns/is_secondary', False): if rnode.name == node.name: raise BundleError(f'{node.name} cannot be its own secondary') for _, found_ips in repo.libs.tools.resolve_identifier(repo, rnode.name).items(): ips.update({str(ip) for ip in found_ips}) return { 'powerdns': { 'my_secondary_servers': ips, }, } @metadata_reactor.provides( 'powerdns/my_primary_servers', ) def get_ips_of_primary_nameservers(metadata): if not metadata.get('powerdns/is_secondary', False): return {} ips = {} for rnode in repo.nodes_in_group('dns'): if not rnode.metadata.get('powerdns/is_secondary', False): if rnode.name == node.name: raise BundleError(f'{node.name} cannot be its own secondary') hostname = rnode.metadata.get('hostname') ips[hostname] = set() for _, found_ips in repo.libs.tools.resolve_identifier(repo, rnode.name).items(): ips[hostname].update({str(ip) for ip in found_ips}) return { 'powerdns': { 'my_primary_servers': ips, }, } @metadata_reactor.provides( 'powerdns/bind-zones/kunbox.net/records', ) def generate_dns_entries_for_nodes(metadata): results = set() for rnode in repo.nodes: node_name_split = rnode.name.split('.') node_name_split.reverse() dns_name = '.'.join(node_name_split) ip4 = None ip6 = None found_ips = repo.libs.tools.resolve_identifier(repo, rnode.name, only_physical=True) for ip in sorted(found_ips['ipv4']): if not ip4 and not ip.is_private: ip4 = ip for ip in sorted(found_ips['ipv6']): if not ip6 and not ip.is_private: ip6 = ip if not (ip4 or ip6) and (found_ips['ipv4'] or found_ips['ipv6']): # do it again, but do not filter out private addresses for ip in sorted(found_ips['ipv4']): if not ip4: ip4 = ip for ip in sorted(found_ips['ipv6']): if not ip6: ip6 = ip if ip4: results.add('{} IN A {}'.format(dns_name, ip4)) if ip6: results.add('{} IN AAAA {}'.format(dns_name, ip6)) return { 'powerdns': { 'bind-zones': { 'kunbox.net': { 'records': results, }, }, }, } @metadata_reactor.provides( 'hosts/entries', ) def hosts_entries_for_all_dns_servers(metadata): entries = {} for rnode in repo.nodes_in_group('dns'): if rnode.name == node.name: continue found_ips = repo.libs.tools.resolve_identifier(repo, rnode.name) for ip in sorted(found_ips['ipv4']): if not ip.is_private: entries[str(ip)] = { rnode.metadata.get('hostname'), rnode.name, } if rnode.metadata.get('powerdns/my_hostname', None): entries[str(ip)].add(rnode.metadata.get('powerdns/my_hostname')) return { 'hosts': { 'entries': entries, }, } @metadata_reactor.provides( 'firewall/port_rules', ) def firewall(metadata): return { 'firewall': { 'port_rules': { '53/tcp': atomic(metadata.get('powerdns/restrict-to/dns', {'*'})), '53/udp': atomic(metadata.get('powerdns/restrict-to/dns', {'*'})), '8081/tcp': atomic(metadata.get('powerdns/restrict-to/api', set())), }, }, }