#!/bin/bash

set -e

install_lxd() {
    # Ubuntu now has the lxd-installer package, which tricks you into thinking
    # lxd is installed, when in fact it's not, so checking for "lxd" in PATH is
    # not enough. Let's just assume that in Ubuntu lxd is always a snap.
    vendor=$(dpkg-vendor --query Vendor)
    if [ "${vendor}" = "Ubuntu" ]; then
        # install the snap if needed
        snap list lxd > /dev/null 2>&1 || {
            echo "Installing the LXD snap..."
            snap install lxd
        }
    else
       if ! command -v lxd > /dev/null 2>&1; then
           echo "ERROR, no lxd found"
           return 1
       fi
    fi
}

wait_container_ready() {
    local container="${1}"
    local -i limit=120 # seconds
    local -i i=0
    local -i result=0
    local ip
    local output

    while /bin/true; do
        ip=$(lxc list "${container}" -c 4 --format=compact | tail -1 | awk '{print $1}')
        if [ -n "${ip}" ]; then
            break
        fi
        i=$((i+1))
        if [ ${i} -ge ${limit} ]; then
            return 1
        fi
        sleep 1s
        echo -n "."
    done
    while ! nc -z "${ip}" 22; do
        echo -n "."
        i=$((i+1))
        if [ ${i} -ge ${limit} ]; then
            return 1
        fi
        sleep 1s
    done
    # cloud-init might still be doing things...
    # this call blocks, so wrap it in its own little timeout
    output=$(lxc exec "${container}" -- timeout --verbose $((limit-i)) cloud-init status --wait) || {
        result=$?
        # 2 is a warning, we will ignore it
        # See LP: #2048522
        if [ ${result} -ne 2 ]; then
            echo "cloud-init status --wait failed on container ${container}"
            echo "${output}"
            return ${result}
        fi
    }
    echo
}

# Copy the local apt package archive over to the lxd container.
copy_local_apt_files() {
    local container_name="${1}"

    for local_source in $(apt-get indextargets | grep-dctrl -F URI -e '^file:/' -sURI | awk '{print $2}'); do
        local_source=${local_source#file:}
        local_dir=$(dirname "${local_source}")
        lxc exec "${container_name}" -- mkdir -p "${local_dir}"
        tar -cC "${local_dir}" . | lxc exec "${container_name}" -- tar -xC "${local_dir}"
    done
}

send_apt_config() {
    echo "Copying over /etc/apt to container ${1}"
    lxc exec "${1}" -- rm -rf /etc/apt
    lxc exec "${1}" -- mkdir -p /etc/apt
    tar -cC /etc/apt . | lxc exec "${1}" -- tar -xC /etc/apt
}

install_packages_in_container() {
    local container="${1}"
    shift

    echo "### Installing dependencies in container: $*"
    lxc exec "${container}" --env DEBIAN_FRONTEND=noninteractive -- apt-get update -q
    lxc exec "${container}" --env DEBIAN_FRONTEND=noninteractive -- apt-get dist-upgrade -q -y
    lxc exec "${container}" --env DEBIAN_FRONTEND=noninteractive -- apt-get install -q -y "$@"
}

wait_socket_open() {
    local sock="${1}"
    echo "Awaiting unix socket at ${sock}"
    local -i limit=120 # seconds
    while ! (netcat -U "${sock}" -N > /dev/null 2>&1); do
        i=$((i+1))
        if [ ${i} -ge ${limit} ]; then
            return 1
        fi
        sleep 1s
        echo -n "."
    done
    echo
}

# =========== main =========== #
XDG_RUNTIME_DIR="/run/user/$(id -u)"
mkdir -p "${XDG_RUNTIME_DIR}"

source /etc/os-release
pkgver=$(dpkg-query -W -f='${Version}' wsdd)
container="lxc-$$"
intf=lxdbr0
sock="${XDG_RUNTIME_DIR}/wsdd.sock"

install_lxd
lxd init --auto

cat <<EOF | lxd init --preseed
networks:
- name: ${intf}
  type: bridge
  config:
    ipv4.address: auto
    ipv6.address: none
EOF

echo "## Launching ${VERSION_CODENAME} container"
lxc launch "ubuntu-daily:${VERSION_CODENAME}" "${container}" -c security.nesting=true
wait_container_ready "${container}"
send_apt_config "${container}"
copy_local_apt_files "${container}"
install_packages_in_container "${container}" "wsdd=${pkgver}"

echo "## Starting wsdd in host mode inside container"
lxc exec "${container}" -- wsdd -vv --ipv4only --interface eth0 </dev/null &

echo "## Starting wsdd in discovery mode"
# Disable http_proxy because wsdd uses HTTP on the local network
http_proxy='' wsdd -vv --ipv4only --interface "${intf}" --no-host --discovery --listen "${sock}" </dev/null &
wait_socket_open "${sock}"

echo "## Listing discovered hosts:"
# Assert that we find a host in the bridged network
echo "list" | netcat -U "${sock}" -N | grep "${intf}"
