# -*- shell-script -*-
# Copyright 2021-2022 Ian Jackson and contributors to Hippotat
# SPDX-License-Identifier: GPL-3.0-or-later WITH LicenseRef-Hippotat-OpenSSL-Exception
# There is NO WARRANTY.

set -o pipefail
set -x

. "${0%/*}"/../test/tcommon

test-prep () {
    determine-tname adt

    if [ "$AUTOPKGTEST_TMP" ]; then
	tmp=$AUTOPKGTEST_TMP
    else
	tmp=$PWD/tmp/$tname
	host-pre-cleanup
	mkdir -p tmp
	rm -rf "$tmp"
	mkdir "$tmp"
    fi
}

filesystem-prep () {
    cs=$1; shift
    # expects $tmp to be set to test-specific temp dir (abs path)

    host-cleanup $cs

    mkdir "$tmp"/$cs-overlay
    
    for fs in root home; do
	case "$fs" in
	    root)	lower=/		;;
	    home)	lower=/home	;;
	    *) x-internal-error	;;
	esac

	rm -rf "$tmp"/$cs-$fs-{upper,work}
	mkdir "$tmp"/$cs-$fs-{upper,work}

	mount -t overlay -o \
 lowerdir=$lower,upperdir="$tmp"/$cs-$fs-upper,workdir="$tmp"/$cs-$fs-work \
	      none "$tmp"/$cs-overlay$lower
    done
    mount -o bind,ro /dev "$tmp"/$cs-overlay/dev
}

host-pre-cleanup () {
    host-cleanup client
    host-cleanup server
}

host-cleanup () {
    cs=$1; shift
    fuser -Mkm "$tmp"/$cs-overlay ||:
    umount "$tmp"/$cs-overlay/proc ||:
    umount "$tmp"/$cs-overlay/dev ||:
    umount "$tmp"/$cs-overlay/home ||:
    umount "$tmp"/$cs-overlay ||:
    umount "$tmp"/$cs-pidns ||:
    if test -d "$tmp"/$cs-overlay; then
	rmdir "$tmp"/$cs-overlay
    fi
}

pidnamespace-prep () {
    cs=$1; shift
    touch "$tmp"/$cs-pidns
    rm -f "$tmp"/$cs-overlay/adt-pidns-sentinel
    mkfifo -m 600 "$tmp"/$cs-overlay/adt-pidns-sentinel
    unshare --fork --pid="$tmp"/$cs-pidns \
	    chroot "$tmp"/$cs-overlay \
	    sh -ec '
		mount -t proc none /proc
		>/adt-pidns-sentinel
		sleep 10000000
	    ' &
    cat "$tmp"/$cs-overlay/adt-pidns-sentinel
}

configure () {
    cs=$1; shift
    in- $cs dd <<END of=/etc/hippotat/secrets.d/alice
[sam 192.0.2.3]
secret = sesame
END
    in- $cs dd <<END of=/etc/hippotat/main.cfg
[COMMON]
server = sam

[sam]
addrs = 198.51.100.1
port = 80
vnetwork = 192.0.2.0/24
END

    in- $cs bash -xe <<'END'
	ln -s ../services-available/ipif /etc/userv/services.d/ipif
END

    configure-$cs
}

configure-client () {
    in- client bash -xe <<'ENDC'
	dd of=/etc/userv/ipif-access/hippo-client <<END
permit group _hippotat ifname hippo%d hostnet 192.0.2.3/24
END
ENDC
}
configure-server () {
    in- server bash -xe <<'ENDS'
	f=/etc/authbind/byport/80
	touch $f
	chgrp _hippotat $f
	chmod 554 $f

	dd of=/etc/userv/ipif-access/hippo-server <<END
permit group _hippotat ifname shippo%d hostnet 192.0.2.1/24
END
ENDS
}

setup-host () {
    cs=$1; shift
    filesystem-prep $cs
    pidnamespace-prep $cs

#    in- $cs ps -efH
#false

    in- $cs bash -xec '
	if test -h /var/cache/apt/archives &&
         ! test -d /var/cache/apt/archives; then
	    rm /var/cache/apt/archives
	fi
    '

    : remove redundant packages
#    apt-mark showmanual |sort >$tmp/$cs-mark-manual
    perl -ne '
	next unless m{^Tests:.*\s'"$tname"'\s}..m{^$};
	next unless m{^Depends:}...m{^\S};
	s{^Depends:}{ };
	next if m{^\S};
	print $_, "\n" foreach split m{[\s,]+};
    ' debian/tests/control |sort >$tmp/$cs-unwanted-deps
    local unwanted_deps=$(perl -ne '
	next if m{^(?:userv-utils|libnetaddr-ip-perl|net-tools)$};
	next if m{^hippotat-'"$cs"'$};
	next if m{^(?:iptables|rsyslog|authbind)$} && '"$cs"' eq "server";
	print;
    ' $tmp/$cs-unwanted-deps)
#    join $tmp/$cs-unwanted-deps
    in- $cs apt-mark auto $unwanted_deps
    in- $cs apt-get -y autoremove

    in- $cs service userv start
    in- $cs service rsyslog start

    configure $cs

    finish-setup-host-$cs
}

finish-setup-host-client () {
    yes '' | \
    in- client adduser --disabled-password user ||:
    in- client adduser user _hippotat
}
finish-setup-host-server () {
    in- server iptables -D INPUT -j empty -s 192.0.2.0/24 ||:
    in- server iptables -N empty ||:
    in- server iptables -I INPUT -j empty -s 192.0.2.0/24
}

in- () {
    cs=$1; shift
    in-ns $cs \
	  nsenter --pid="$tmp"/$cs-pidns \
	  chroot "$tmp"/$cs-overlay \
	  "$@"
}

setup-pair () {
    test-prep
    $test/netns-setup $tname
    setup-host client
    setup-host server
}
