This commit is contained in:
2020-08-17 12:06:41 -04:00
parent 9fa09f26bd
commit 6eb48873e6
455 changed files with 45184 additions and 14 deletions

View File

@@ -0,0 +1,117 @@
---
- name: Converge
hosts: all
vars:
bind_zone_dir: /var/local/named-zones
bind_zone_file_mode: '0660'
bind_allow_query:
- any
bind_listen_ipv4:
- any
bind_listen_ipv6:
- any
bind_acls:
- name: acl1
match_list:
- 172.17.0.0/16
bind_forwarders:
- '8.8.8.8'
- '8.8.4.4'
bind_recursion: true
bind_query_log: 'data/query.log'
bind_check_names: 'master ignore'
bind_zone_master_server_ip: 172.17.0.2
bind_zone_minimum_ttl: "2D"
bind_zone_ttl: "2W"
bind_zone_time_to_refresh: "2D"
bind_zone_time_to_retry: "2H"
bind_zone_time_to_expire: "2W"
bind_zone_domains:
- name: 'example.com'
networks:
- '192.0.2'
ipv6_networks:
- '2001:db9::/48'
name_servers:
- ns1.acme-inc.com.
- ns2.acme-inc.com.
hostmaster_email: admin
hosts:
- name: srv001
ip: 192.0.2.1
ipv6: '2001:db9::1'
aliases:
- www
- name: srv002
ip: 192.0.2.2
ipv6: '2001:db9::2'
- name: mail001
ip: 192.0.2.10
ipv6: '2001:db9::3'
mail_servers:
- name: mail001
preference: 10
- name: 'acme-inc.com'
networks:
- '172.17'
- '10'
ipv6_networks:
- '2001:db8::/48'
name_servers:
- ns1
- ns2
hosts:
- name: ns1
ip: 172.17.0.2
- name: ns2
ip: 172.17.0.3
- name: srv001
ip: 172.17.1.1
ipv6: 2001:db8::1
aliases:
- www
- name: srv002
ip: 172.17.1.2
ipv6: 2001:db8::2
aliases:
- mysql
- name: mail001
ip: 172.17.2.1
ipv6: 2001:db8::d:1
aliases:
- smtp
- mail-in
- name: mail002
ip: 172.17.2.2
ipv6: 2001:db8::d:2
- name: mail003
ip: 172.17.2.3
ipv6: 2001:db8::d:3
aliases:
- imap
- mail-out
- name: srv010
ip: 10.0.0.10
- name: srv011
ip: 10.0.0.11
- name: srv012
ip: 10.0.0.12
mail_servers:
- name: mail001
preference: 10
- name: mail002
preference: 20
services:
- name: _ldap._tcp
weight: 100
port: 88
target: srv010
text:
- name: _kerberos
text: KERBEROS.ACME-INC.COM
- name: '@'
text:
- 'some text'
- 'more text'
roles:
- role: bertvv.bind

View File

@@ -0,0 +1,263 @@
#! /usr/bin/env bats
#
# Functional tests for a DNS server set up as a test case for Ansible role
# bertvv.bind
#
# The variable SUT_IP, the IP address of the System Under Test must be set
# outside of the script.
#{{{ Helper functions
# Usage: assert_forward_lookup NAME DOMAIN IP
# Exits with status 0 if NAME.DOMAIN resolves to IP, a nonzero
# status otherwise
assert_forward_lookup() {
local name="$1"
local domain="$2"
local ip="$3"
local result
result=$(dig @"${SUT_IP}" "${name}.${domain}" +short)
echo "Expected: ${ip}"
echo "Actual : ${result}"
[ "${ip}" = "${result}" ]
}
# Usage: assert_forward_ipv6_lookup NAME DOMAIN IP
assert_forward_ipv6_lookup() {
local name="${1}"
local domain="${2}"
local ip="${3}"
local result
result=$(dig @"${SUT_IP}" AAAA "${name}.${domain}" +short)
echo "Expected: ${ip}"
echo "Actual : ${result}"
[ "${ip}" = "${result}" ]
}
# Usage: assert_reverse_lookup NAME DOMAIN IP
# Exits with status 0 if a reverse lookup on IP resolves to NAME,
# a nonzero status otherwise
assert_reverse_lookup() {
local name="$1"
local domain="$2"
local ip="$3"
local expected="${name}.${domain}."
local result
result=$(dig @"${SUT_IP}" -x "${ip}" +short)
echo "Expected: ${expected}"
echo "Actual : ${result}"
[ "${expected}" = "${result}" ]
}
# Usage: assert_alias_lookup ALIAS NAME DOMAIN IP
# Exits with status 0 if a forward lookup on NAME resolves to the
# host name NAME.DOMAIN and to IP, a nonzero status otherwise
assert_alias_lookup() {
local alias="$1"
local name="$2"
local domain="$3"
local ip="$4"
local result
result=$(dig @"${SUT_IP}" "${alias}.${domain}" +short)
grep "${name}\\.${domain}\\." <<< "${result}"
grep "${ip}" <<< "${result}"
}
# Usage: assert_ns_lookup DOMAIN NS_NAME...
# Exits with status 0 if all specified host names occur in the list of
# name servers for the domain.
assert_ns_lookup() {
local domain="${1}"
shift
local result
result=$(dig @"${SUT_IP}" "${domain}" NS +short)
[ -n "${result}" ] # the list of name servers should not be empty
while (( "$#" )); do
grep "$1\\." <<< "${result}"
shift
done
}
# Usage: assert_mx_lookup DOMAIN PREF1 NAME1 PREF2 NAME2...
# e.g. assert_mx_lookup example.com 10 mailsrv1 20 mailsrv2
# Exits with status 0 if all specified host names occur in the list of
# mail servers for the domain.
assert_mx_lookup() {
local domain="${1}"
shift
local result
result=$(dig @"${SUT_IP}" "${domain}" MX +short)
[ -n "${result}" ] # the list of name servers should not be empty
while (( "$#" )); do
grep "$1 $2\\.${domain}\\." <<< "${result}"
shift
shift
done
}
# Usage: assert_srv_lookup DOMAIN SERVICE WEIGHT PORT TARGET
# e.g. assert_srv_lookup example.com _ldap._tcp 0 100 88 ldapsrv
assert_srv_lookup() {
local domain="${1}"
shift
local service="${1}"
shift
local expected="${*}.${domain}."
local result
result=$(dig @"${SUT_IP}" SRV "${service}.${domain}" +short)
echo "expected: ${expected}"
echo "actual : ${result}"
[ "${result}" = "${expected}" ]
}
# Perform a TXT record lookup
# Usage: assert_txt_lookup NAME TEXT...
# e.g. assert_txt_lookup _kerberos.example.com KERBEROS.EXAMPLE.COM
assert_txt_lookup() {
local name="$1"
shift
local result
result=$(dig @"${SUT_IP}" TXT "${name}" +short)
echo "expected: ${*}"
echo "actual : ${result}"
while [ "$#" -ne "0" ]; do
grep "${1}" <<< "${result}"
shift
done
}
#}}}
@test "Forward lookups acme-inc.com" {
# host name domain IP
assert_forward_lookup ns1 acme-inc.com 172.17.0.2
assert_forward_lookup ns2 acme-inc.com 172.17.0.3
assert_forward_lookup srv001 acme-inc.com 172.17.1.1
assert_forward_lookup srv002 acme-inc.com 172.17.1.2
assert_forward_lookup mail001 acme-inc.com 172.17.2.1
assert_forward_lookup mail002 acme-inc.com 172.17.2.2
assert_forward_lookup mail003 acme-inc.com 172.17.2.3
assert_forward_lookup srv010 acme-inc.com 10.0.0.10
assert_forward_lookup srv011 acme-inc.com 10.0.0.11
assert_forward_lookup srv012 acme-inc.com 10.0.0.12
}
@test "Reverse lookups acme-inc.com" {
# host name domain IP
assert_reverse_lookup ns1 acme-inc.com 172.17.0.2
assert_reverse_lookup ns2 acme-inc.com 172.17.0.3
assert_reverse_lookup srv001 acme-inc.com 172.17.1.1
assert_reverse_lookup srv002 acme-inc.com 172.17.1.2
assert_reverse_lookup mail001 acme-inc.com 172.17.2.1
assert_reverse_lookup mail002 acme-inc.com 172.17.2.2
assert_reverse_lookup mail003 acme-inc.com 172.17.2.3
assert_reverse_lookup srv010 acme-inc.com 10.0.0.10
assert_reverse_lookup srv011 acme-inc.com 10.0.0.11
assert_reverse_lookup srv012 acme-inc.com 10.0.0.12
}
@test "Alias lookups acme-inc.com" {
# alias hostname domain IP
assert_alias_lookup www srv001 acme-inc.com 172.17.1.1
assert_alias_lookup mysql srv002 acme-inc.com 172.17.1.2
assert_alias_lookup smtp mail001 acme-inc.com 172.17.2.1
assert_alias_lookup mail-in mail001 acme-inc.com 172.17.2.1
assert_alias_lookup imap mail003 acme-inc.com 172.17.2.3
assert_alias_lookup mail-out mail003 acme-inc.com 172.17.2.3
}
@test "IPv6 forward lookups acme-inc.com" {
# hostname domain IPv6
assert_forward_ipv6_lookup srv001 acme-inc.com 2001:db8::1
assert_forward_ipv6_lookup srv002 acme-inc.com 2001:db8::2
assert_forward_ipv6_lookup mail001 acme-inc.com 2001:db8::d:1
assert_forward_ipv6_lookup mail002 acme-inc.com 2001:db8::d:2
assert_forward_ipv6_lookup mail003 acme-inc.com 2001:db8::d:3
}
@test "IPv6 reverse lookups acme-inc.com" {
# hostname domain IPv6
assert_forward_ipv6_lookup srv001 acme-inc.com 2001:db8::1
assert_forward_ipv6_lookup srv002 acme-inc.com 2001:db8::2
assert_forward_ipv6_lookup mail001 acme-inc.com 2001:db8::d:1
assert_forward_ipv6_lookup mail002 acme-inc.com 2001:db8::d:2
assert_forward_ipv6_lookup mail003 acme-inc.com 2001:db8::d:3
}
@test "NS record lookup acme-inc.com" {
assert_ns_lookup acme-inc.com \
ns1.acme-inc.com \
ns2.acme-inc.com
}
@test "Mail server lookup acme-inc.com" {
assert_mx_lookup acme-inc.com \
10 mail001 \
20 mail002
}
@test "Service record lookup acme-inc.com" {
assert_srv_lookup acme-inc.com _ldap._tcp 0 100 88 srv010
}
@test "TXT record lookup acme-inc.com" {
assert_txt_lookup _kerberos.acme-inc.com KERBEROS.ACME-INC.COM
assert_txt_lookup acme-inc.com "some text" "more text"
}
# Tests for domain example.com
@test "Forward lookups example.com" {
# host name domain IP
assert_forward_lookup srv001 example.com 192.0.2.1
assert_forward_lookup srv002 example.com 192.0.2.2
assert_forward_lookup mail001 example.com 192.0.2.10
}
@test "Reverse lookups example.com" {
# host name domain IP
assert_reverse_lookup srv001 example.com 192.0.2.1
assert_reverse_lookup srv002 example.com 192.0.2.2
assert_reverse_lookup mail001 example.com 192.0.2.10
}
@test "Alias lookups example.com" {
# alias hostname domain IP
assert_alias_lookup www srv001 example.com 192.0.2.1
}
@test "IPv6 forward lookups example.com" {
# hostname domain IPv6
assert_forward_ipv6_lookup srv001 example.com 2001:db9::1
}
@test "IPv6 reverse lookups example.com" {
# hostname domain IPv6
assert_reverse_lookup srv001 example.com 2001:db9::1
}
@test "NS record lookup example.com" {
assert_ns_lookup example.com \
ns1.acme-inc.com \
ns2.acme-inc.com
}
@test "Mail server lookup example.com" {
assert_mx_lookup example.com \
10 mail001
}

View File

@@ -0,0 +1,117 @@
#! /usr/bin/env bash
#
# Author: Bert Van Vreckem <bert.vanvreckem@gmail.com>
#
# Run BATS test files in the current directory, and the ones in the subdirectory
# matching the host name.
#
# The script installs BATS if needed. It's best to put ${bats_install_dir} in
# your .gitignore.
set -o errexit # abort on nonzero exitstatus
set -o nounset # abort on unbound variable
#{{{ Variables
test_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
bats_archive="v0.4.0.tar.gz"
bats_url="https://github.com/sstephenson/bats/archive/${bats_archive}"
bats_install_dir="/opt"
bats_default_location="${bats_install_dir}/bats/libexec/bats"
test_file_pattern="*.bats"
# Color definitions
readonly reset='\e[0m'
readonly black='\e[0;30m'
readonly red='\e[0;31m'
readonly green='\e[0;32m'
readonly yellow='\e[0;33m'
readonly blue='\e[0;34m'
readonly purple='\e[0;35m'
readonly cyan='\e[0;36m'
readonly white='\e[0;37m'
#}}}
main() {
bats=$(find_bats_executable)
if [ -z "${bats}" ]; then
install_bats
bats="${bats_default_location}"
fi
debug "Using BATS executable at: ${bats}"
# List all test cases (i.e. files in the test dir matching the test file
# pattern)
# Tests to be run on all hosts
global_tests=$(find_tests "${test_dir}" 1)
# Tests for individual hosts
host_tests=$(find_tests "${test_dir}/${HOSTNAME}")
# Loop over test files
for test_case in ${global_tests} ${host_tests}; do
info "Running test ${test_case}"
${bats} "${test_case}"
done
}
#{{{ Functions
# Tries to find BATS executable in the PATH or the place where this script
# installs it.
find_bats_executable() {
if which bats > /dev/null; then
which bats
elif [ -x "${bats_default_location}" ]; then
echo "${bats_default_location}"
else
echo ""
fi
}
# Usage: install_bats
install_bats() {
pushd "${bats_install_dir}" > /dev/null 2>&1
curl --location --remote-name "${bats_url}"
tar xzf "${bats_archive}"
mv bats-* bats
rm "${bats_archive}"
popd > /dev/null 2>&1
}
# Usage: find_tests DIR [MAX_DEPTH]
#
# Finds BATS test suites in the specified directory
find_tests() {
local max_depth=""
if [ "$#" -eq "2" ]; then
max_depth="-maxdepth $2"
fi
local tests
tests=$(find "$1" ${max_depth} -type f -name "${test_file_pattern}" -printf '%p\n' 2> /dev/null)
echo "${tests}"
}
# Usage: info [ARG]...
#
# Prints all arguments on the standard output stream
info() {
printf "${yellow}### %s${reset}\n" "${*}"
}
# Usage: debug [ARG]...
#
# Prints all arguments on the standard output stream
debug() {
printf "${cyan}### %s${reset}\n" "${*}"
}
#}}}
main

View File

@@ -0,0 +1,53 @@
---
dependency:
name: galaxy
driver:
# Specifies the driver that should be used. Podman should also work
name: docker
# Linting with yamllint and ansible-lint
# verify.yml is skipped because it uses the shell: module, which would trigger
# a linting error.
lint: |
yamllint .
ansible-lint --exclude=molecule/default/verify.yml
platforms:
# Set name and hostname
- name: ns1
hostname: ns1
# Specify which image should be used. Geerlingguys images are Ansible
# compatible and have Systemd installed
image: "geerlingguy/docker-${MOLECULE_DISTRO:-centos7}-ansible:latest"
# Command to execute when the container starts
command: ${MOLECULE_DOCKER_COMMAND:-""}
# Volumes to mount within the container. Important to enable systemd
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
# Give extended privileges to the container. Necessary for Systemd to
# operate within the container. DO NOT use extended privileges in a
# production environment!
privileged: true
# Allocate pseudo-TTY
tty: true
environment:
container: docker
- name: ns2
hostname: ns2
image: "geerlingguy/docker-${MOLECULE_DISTRO:-centos7}-ansible:latest"
command: ${MOLECULE_DOCKER_COMMAND:-""}
volumes:
- /sys/fs/cgroup:/sys/fs/cgroup:rw
privileged: true
tty: true
environment:
container: docker
provisioner:
name: ansible
# Runs the verify.yml playbook
verifier:
name: ansible

View File

@@ -0,0 +1,9 @@
---
- name: Verify
hosts: all
tasks:
# We run the BATS tests from the localhost, since they are black box tests
- name: "Run BATS tests for {{ ansible_hostname }}"
shell: SUT_IP={{ ansible_default_ipv4.address }} bats {{ playbook_dir }}/files/dns.bats
delegate_to: localhost
changed_when: false