#!/bin/bash

# Author: Daniel Kahn Gillmor <dkg@fifthhorseman.net>
# 2018-11-02
# License: GPLv3+

# error on exit
set -e
# for handling jobspecs:
set -m

if [ -z "$AUTOPKGTEST_ARTIFACTS" ]; then
    d="$(mktemp -d)"
    remove="$d"
else
    d="$AUTOPKGTEST_ARTIFACTS"
fi
ip="${TESTIP:-127.$(( $RANDOM % 256 )).$(( $RANDOM % 256 )).$(( $RANDOM % 256 ))}"
port="${PORT:-8123}"
knotd="${KNOTD:-/usr/sbin/knotd}"
kdig="${KDIG:-$(which kdig)}"
kzonecheck="${KZONECHECK:-$(which kzonecheck)}"
knotc="${KNOTC:-/usr/sbin/knotc}"
test_address="${TEST_ADDRESS:-192.0.2.199}"
get_kaspdb="${GET_KASPDB:-/usr/lib/knot/get_kaspdb}"
get_user="${GET_USER:-/usr/lib/knot/get_user}"
kasp_json2lmdb="${KASP_JSON2LMDB:-/usr/lib/knot/kasp_json2lmdb}"

declare -a knot_args=(--socket "$d/knot.sock" --config="$d/knot.conf" --verbose)

printf "%s + %s roundtrip tests\n------------\n    workdir: %s\n    IP addr: %s\n  knot args: %s\n" "$knotd" "$kdig" "$d" "$ip" "${knot_args[*]}"

section() {
    printf "\n%s\n" "$1"
    sed 's/./-/g' <<<"$1"
}

cleanup () {
    section "cleaning up"
    find "$d" -ls
    "${knotc}" "${knot_args[@]}" stop
    wait %1
    tail -n +1 -v "$d"/*.err
    if [ "$remove" ]; then
        printf "\ncleaning up working directory %s\n" "$remove"
        rm -rf "$remove"
    fi
}
trap cleanup EXIT

section "set up config file and zonefile"

user=$(id -nu)
group=$(id -ng)
cat > "$d/knot.conf" <<EOF
server:
 rundir: "$d/run"
 listen: $ip@$port
 user: $user:$group
template:
 - id: default
   storage: "$d"
   file: "%s.zone"
zone:
 - domain: example.net
EOF

cat > "$d/example.net.zone" <<EOF
@ 1D IN SOA a.ns hostmaster 2018103100 3h 15m 1w 1d
@ 1D IN NS a.ns.example.net.
@ 1D IN NS b.ns.example.net.
a.ns 1D IN A 192.0.2.1
b.ns 1D IN A 192.0.2.2
test 1D IN A $test_address
EOF

mkdir -p "$d/kasp-db/keys"
keytime="$(TZ=UTC date +%FT%T%z -d 'yesterday')"
cat >"$d/kasp-db/zone_example.net.json" <<EOF
{
  "policy": "default",
  "nsec3_salt": null,
  "nsec3_salt_created": null,
  "keys": [
    {
      "id": "ff81022ffd8e16256b3ac8e136f5f068fbe9b714",
      "keytag": 24401,
      "algorithm": 13,
      "public_key": "6J7vEzP9NI/vgkLRToCmgNZ8XOWoUrwrSJyxqcL8Ll/t1Ucy6arTtzsjBQ32SDJEHfQhg0u/fABsp9HVZnFo3g==",
      "ksk": true,
      "created": "$keytime",
      "publish": "$keytime",
      "active": "$keytime"
    },
    {
      "id": "bf033546160229f56a8c90ca6ed3b599060b0067",
      "keytag": 46765,
      "algorithm": 13,
      "public_key": "TczXowY+XyfUlvHFThLnPnM1zL/kH9lJP1B+WbhgksgHt/Bt93RrOWMgASoYWlBgW2uTVqqoNzLCk9YbPz5ViA==",
      "ksk": false,
      "created": "$keytime",
      "publish": "$keytime",
      "active": "$keytime"
    }
  ]
}
EOF
cat > "$d/kasp-db/keys/bf033546160229f56a8c90ca6ed3b599060b0067.pem" <<EOF
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgEVKLYtyI4lZ7JiAM
xziZ/May2VI20QseJGS2AD0U3HKgCgYIKoZIzj0DAQehRANCAARNzNejBj5fJ9SW
8cVOEuc+czXMv+Qf2Uk/UH5ZuGCSyAe38G33dGs5YyABKhhaUGBba5NWqqg3MsKT
1hs/PlWI
-----END PRIVATE KEY-----
EOF
cat > "$d/kasp-db/keys/ff81022ffd8e16256b3ac8e136f5f068fbe9b714.pem" <<EOF
-----BEGIN PRIVATE KEY-----
MIGUAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHoweAIBAQQhALYx6iXAqIQPL8aI
Bw0RtWKEOMSW/XawlfPM+7Gdkx9GoAoGCCqGSM49AwEHoUQDQgAE6J7vEzP9NI/v
gkLRToCmgNZ8XOWoUrwrSJyxqcL8Ll/t1Ucy6arTtzsjBQ32SDJEHfQhg0u/fABs
p9HVZnFo3g==
-----END PRIVATE KEY-----                                                       
EOF


find "$d" -maxdepth 1 -type f -print0 | xargs -0 tail -n +1 -v 

mkdir -p "${d}/run"

section "kzonecheck'ing zonefile"
"${kzonecheck}" -v "$d/example.net.zone"

section "launching knot"
"${knotd}" "${knot_args[@]}" 2> "$d/knotd.err" &

# FIXME: this is an annoying poll -- would be better if we could be
# alerted when the daemon is done setting up the socket, but i don't
# want to "--daemonize" if i can avoid it because i want the shell to
# remain in direct supervision of all its processes
tried=0
while [ $tried -lt 10 ] ; do
    if "${knotc}" "${knot_args[@]}" status 2>&1; then
        break;
    fi
    sleep 0.5
    tried=$(( $tried + 1 ))
done
if [ $tried -ge 10 ]; then
    printf "failed to use %s\n" "${knotc}" >&2
    exit 1
fi


section "querying knot"
"${kdig}" -p "${port}" @"${ip}" -t A test.example.net test2.example.net
answer="$("${kdig}" +short -p "${port}" @"${ip}" -t A test.example.net)"
if ! [ "$answer" = "$test_address" ]; then
    printf "test.example.net mismatch!\nexpected: %s\n     got: %s\n" "$test_address" "$answer" >&2
    exit 1
fi
answer2="$("${kdig}" +short -p "${port}" @"${ip}" -t A test2.example.net)"
if ! [ "$answer2" = "" ]; then
    printf "test2.example.net gave unexpected answer!\n  got: %s\n" "$answer2" >&2
    exit 1
fi

section "modifying zone"
printf "test2 1D IN A $test_address\n" >>"$d/example.net.zone"
sed -i 's/^@ 1D IN SOA.*/@ 1D IN SOA a.ns hostmaster 2018110100 3h 15m 1w 1d/' "$d/example.net.zone"
"${knotc}" "${knot_args[@]}" reload

section "querying again"
"${kdig}" -p "${port}" @"${ip}" -t A test.example.net test2.example.net
answer="$("${kdig}" +short -p "${port}" @"${ip}" -t A test.example.net)"
if ! [ "$answer" = "$test_address" ]; then
    printf "test.example.net mismatch!\nexpected: %s\n     got: %s\n" "$test_address" "$answer" >&2
    exit 1
fi
answer2="$("${kdig}" +short -p "${port}" @"${ip}" -t A test2.example.net)"
if ! [ "$answer2" = "$test_address" ]; then
    printf "test2.example.net mismatch!\nexpected: %s\n     got: %s\n" "$test_address" "$answer2" >&2
    exit 1
fi

section "testing python transition helpers"
"${get_kaspdb}" "$d/knot.conf"
got_user="$(${get_user} "$d/knot.conf")"
if [ "$got_user" != "$user" ]; then
    printf "user account mismatch!\nexpected: %s\n     got: %s\n" "$user" "$got_user" >&2
    exit 1
fi
"${kasp_json2lmdb}" --import "$d/kasp-db"

