#!/bin/bash
set -euo pipefail

export VM=clevis

title() {
    [ -z "${1}" ] && return 0
    printf '\n\n\n### %s\n' "${@}"
    return 0
}

cmd() {
    [ -z "${1}" ] && return 0
    ssh "${VM}" "${@}"
}

is_unlocked() {
    dev=${1:-}
    [ -z "${dev}" ] && echo "ERROR" && return 0
    luks_uuid="$(cmd cryptsetup luksUUID ${dev} | sed -e 's/-//'g)"
    if cmd test -b /dev/disk/by-id/dm-uuid-*"${luks_uuid}"*; then
        echo "YES"
        return 0
    fi
    echo "NO"
}

wait_for_vm() {
    local _timeout=${1:-120}
    echo "[$(date)] Waiting up to ${_timeout} seconds for VM to respond..." >&2
    local _start _elapsed
    _start=${SECONDS}
    while /bin/true; do
        cmd ls 2>/dev/null >/dev/null && break
        _elapsed=$((SECONDS - _start))
        [ "${_elapsed}" -gt "${_timeout}" ] && echo "[$(date)] TIMEOUT reached" >&2 && return 1

        sleep 0.1
    done
    _elapsed=$((SECONDS - _start))
    echo "[$(date)] VM is up in ${_elapsed} seconds!" >&2
    return 0
}

setup_host() {
    ip a >&2
    free -m >&2

    sudo systemctl restart tangd-update
}

setup_vm() {
    CWD="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"
    set -x

    mkdir -p ~/.ssh
    chmod 700 ~/.ssh
    ssh-keygen -q -t rsa -b 4096 -N '' -f ~/.ssh/id_rsa <<<y 2>&1 >/dev/null
    rm -f ~/.ssh/known_hosts

    cat << EOF > ~/.ssh/config
host clevis
        user root
        hostname 192.168.122.100
        StrictHostKeyChecking no
        ConnectTimeout 20
        PasswordAuthentication no
        PreferredAuthentications publickey
        GSSAPIAuthentication no
EOF

    chmod 600 ~/.ssh/config
    PUBKEY="$(< ~/.ssh/id_rsa.pub)"

    NAME=clevis-vm
    DATA=/data
    DISK=${DATA}/disk.qcow2

    KS=${DATA}/ks.cfg

    case "${DISTRO}" in
    fedora:32)
        COMPOSE=https://download.fedoraproject.org/pub/fedora/linux/releases/32/Everything/x86_64/os/
        KS_TEMPLATE=${CWD}/fedora.cfg.in
        ;;
    fedora:rawhide)
        COMPOSE=https://download.fedoraproject.org/pub/fedora/linux/development/rawhide/Everything/x86_64/os/
        KS_TEMPLATE=${CWD}/fedora.cfg.in
        ;;
    centos:8)
        COMPOSE=http://mirror.centos.org/centos/8/BaseOS/x86_64/os/
        KS_TEMPLATE=${CWD}/centos.cfg.in
        ;;
    centos:8-stream)
        COMPOSE=http://mirror.centos.org/centos/8-stream/BaseOS/x86_64/os/
        KS_TEMPLATE=${CWD}/centos.cfg.in
        ;;
    *)
        echo "Unsupported distro [${DISTRO}]" >&2
        exit 1
        ;;
    esac

    sudo mkdir -m755 -p "${DATA}"
    pushd "${DATA}"

    cat "${KS_TEMPLATE}" \
        | sed -e "s#@PUBKEY@#${PUBKEY}#g" \
        | sed -e "s#@COMPOSE@#${COMPOSE}#g" \
        | sed -e "s#@TRAVIS_REPO_SLUG@#${TRAVIS_REPO_SLUG}#g" \
        | sed -e "s#@TRAVIS_COMMIT@#${TRAVIS_COMMIT}#g" \
        | sudo tee ${KS}

    sudo chown libvirt-qemu:kvm "${DATA}" -R

    sudo virt-install --name=${NAME} --ram=2048 \
        --os-variant=generic --os-type=linux --vcpus=1 --graphics=none \
        --disk=path="${DISK}",size=7,bus=virtio,format=qcow2 \
        --location="${COMPOSE}" --initrd-inject="${KS}" \
        --extra-args="ip=dhcp ks=file:/ks.cfg inst.repo=${COMPOSE} net.ifnames=0 biosdevname=0 console=tty0 console=ttyS0,115200n8 serial" \
        --console pty,target_type=serial --noreboot

    set +x
}

title "host setup"
setup_host

title "VM setup"
setup_vm

# Start VM.
title "Start VM"
sudo virsh start "${NAME}"

title "Verify dracut boot unlocker"
# Check if it booted properly (i.e. unlocked on boot).
if ! wait_for_vm; then
    echo "[FAIL] Unable to verify the VM booted properly" >&2
    exit 1
fi

title "fstab"
cmd "cat /etc/fstab"

title "crypttab"
cmd "cat /etc/crypttab"

title "Block devices"
cmd "lsblk --fs"

title "LUKS devices"

# Check LUKS devices and config.
for dev in $(cmd "lsblk -p -n -s -r " \
            | awk '$6 == "crypt" { getline; print $1 }' | sort -u); do
    echo "DEVICE[${dev}] CONFIG[$(cmd clevis luks list -d ${dev})] UNLOCKED[$(is_unlocked "${dev}")]"
done

title "clevis-luks-askpass journal"

cmd "journalctl -xe -u clevis-luks-askpass"

echo
echo "[PASS] Test completed successfully" >&2
exit 0